1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup spimage
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "DNA_node_types.h"
28 #include "DNA_scene_types.h"
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_utildefines.h"
34 
35 #include "BLT_translation.h"
36 
37 #include "BKE_context.h"
38 #include "BKE_image.h"
39 #include "BKE_node.h"
40 #include "BKE_scene.h"
41 #include "BKE_screen.h"
42 
43 #include "RE_pipeline.h"
44 
45 #include "IMB_colormanagement.h"
46 #include "IMB_imbuf.h"
47 #include "IMB_imbuf_types.h"
48 
49 #include "ED_gpencil.h"
50 #include "ED_image.h"
51 #include "ED_screen.h"
52 
53 #include "RNA_access.h"
54 
55 #include "WM_api.h"
56 #include "WM_types.h"
57 
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60 
61 #include "image_intern.h"
62 
63 #define B_NOP -1
64 #define MAX_IMAGE_INFO_LEN 128
65 
66 /* gets active viewer user */
ntree_get_active_iuser(bNodeTree * ntree)67 struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
68 {
69   bNode *node;
70 
71   if (ntree) {
72     for (node = ntree->nodes.first; node; node = node->next) {
73       if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
74         if (node->flag & NODE_DO_OUTPUT) {
75           return node->storage;
76         }
77       }
78     }
79   }
80   return NULL;
81 }
82 
83 /* ********************* callbacks for standard image buttons *************** */
84 
ui_imageuser_slot_menu(bContext * UNUSED (C),uiLayout * layout,void * image_p)85 static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *image_p)
86 {
87   uiBlock *block = uiLayoutGetBlock(layout);
88   Image *image = image_p;
89   int slot_id;
90 
91   uiDefBut(block,
92            UI_BTYPE_LABEL,
93            0,
94            IFACE_("Slot"),
95            0,
96            0,
97            UI_UNIT_X * 5,
98            UI_UNIT_Y,
99            NULL,
100            0.0,
101            0.0,
102            0,
103            0,
104            "");
105   uiItemS(layout);
106 
107   slot_id = BLI_listbase_count(&image->renderslots) - 1;
108   for (RenderSlot *slot = image->renderslots.last; slot; slot = slot->prev) {
109     char str[64];
110     if (slot->name[0] != '\0') {
111       BLI_strncpy(str, slot->name, sizeof(str));
112     }
113     else {
114       BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot_id + 1);
115     }
116     uiDefButS(block,
117               UI_BTYPE_BUT_MENU,
118               B_NOP,
119               str,
120               0,
121               0,
122               UI_UNIT_X * 5,
123               UI_UNIT_X,
124               &image->render_slot,
125               (float)slot_id,
126               0.0,
127               0,
128               -1,
129               "");
130     slot_id--;
131   }
132 }
133 
ui_imageuser_slot_menu_step(bContext * C,int direction,void * image_p)134 static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_p)
135 {
136   Image *image = image_p;
137 
138   if (ED_image_slot_cycle(image, direction)) {
139     WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
140     return true;
141   }
142   return true;
143 }
144 
ui_imageuser_layer_fake_name(RenderResult * rr)145 static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
146 {
147   RenderView *rv = RE_RenderViewGetById(rr, 0);
148   if (rv->rectf) {
149     return IFACE_("Composite");
150   }
151   if (rv->rect32) {
152     return IFACE_("Sequence");
153   }
154   return NULL;
155 }
156 
157 /* workaround for passing many args */
158 struct ImageUI_Data {
159   Image *image;
160   ImageUser *iuser;
161   int rpass_index;
162 };
163 
ui_imageuser_data_copy(const struct ImageUI_Data * rnd_pt_src)164 static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src)
165 {
166   struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__);
167   memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src));
168   return rnd_pt_dst;
169 }
170 
ui_imageuser_layer_menu(bContext * UNUSED (C),uiLayout * layout,void * rnd_pt)171 static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
172 {
173   struct ImageUI_Data *rnd_data = rnd_pt;
174   uiBlock *block = uiLayoutGetBlock(layout);
175   Image *image = rnd_data->image;
176   ImageUser *iuser = rnd_data->iuser;
177   Scene *scene = iuser->scene;
178   RenderResult *rr;
179   RenderLayer *rl;
180   RenderLayer rl_fake = {NULL};
181   const char *fake_name;
182   int nr;
183 
184   /* may have been freed since drawing */
185   rr = BKE_image_acquire_renderresult(scene, image);
186   if (UNLIKELY(rr == NULL)) {
187     return;
188   }
189 
190   UI_block_layout_set_current(block, layout);
191   uiLayoutColumn(layout, false);
192 
193   uiDefBut(block,
194            UI_BTYPE_LABEL,
195            0,
196            IFACE_("Layer"),
197            0,
198            0,
199            UI_UNIT_X * 5,
200            UI_UNIT_Y,
201            NULL,
202            0.0,
203            0.0,
204            0,
205            0,
206            "");
207   uiItemS(layout);
208 
209   nr = BLI_listbase_count(&rr->layers) - 1;
210   fake_name = ui_imageuser_layer_fake_name(rr);
211 
212   if (fake_name) {
213     BLI_strncpy(rl_fake.name, fake_name, sizeof(rl_fake.name));
214     nr += 1;
215   }
216 
217   for (rl = rr->layers.last; rl; rl = rl->prev, nr--) {
218   final:
219     uiDefButS(block,
220               UI_BTYPE_BUT_MENU,
221               B_NOP,
222               rl->name,
223               0,
224               0,
225               UI_UNIT_X * 5,
226               UI_UNIT_X,
227               &iuser->layer,
228               (float)nr,
229               0.0,
230               0,
231               -1,
232               "");
233   }
234 
235   if (fake_name) {
236     fake_name = NULL;
237     rl = &rl_fake;
238     goto final;
239   }
240 
241   BLI_assert(nr == -1);
242 
243   BKE_image_release_renderresult(scene, image);
244 }
245 
ui_imageuser_pass_menu(bContext * UNUSED (C),uiLayout * layout,void * rnd_pt)246 static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
247 {
248   struct ImageUI_Data *rnd_data = rnd_pt;
249   uiBlock *block = uiLayoutGetBlock(layout);
250   Image *image = rnd_data->image;
251   ImageUser *iuser = rnd_data->iuser;
252   /* (rpass_index == -1) means composite result */
253   const int rpass_index = rnd_data->rpass_index;
254   Scene *scene = iuser->scene;
255   RenderResult *rr;
256   RenderLayer *rl;
257   RenderPass *rpass;
258   int nr;
259 
260   /* may have been freed since drawing */
261   rr = BKE_image_acquire_renderresult(scene, image);
262   if (UNLIKELY(rr == NULL)) {
263     return;
264   }
265 
266   rl = BLI_findlink(&rr->layers, rpass_index);
267 
268   UI_block_layout_set_current(block, layout);
269   uiLayoutColumn(layout, false);
270 
271   uiDefBut(block,
272            UI_BTYPE_LABEL,
273            0,
274            IFACE_("Pass"),
275            0,
276            0,
277            UI_UNIT_X * 5,
278            UI_UNIT_Y,
279            NULL,
280            0.0,
281            0.0,
282            0,
283            0,
284            "");
285 
286   uiItemS(layout);
287 
288   nr = (rl == NULL) ? 1 : 0;
289 
290   ListBase added_passes;
291   BLI_listbase_clear(&added_passes);
292 
293   /* rendered results don't have a Combined pass */
294   /* multiview: the ordering must be ascending, so the left-most pass is always the one picked */
295   for (rpass = rl ? rl->passes.first : NULL; rpass; rpass = rpass->next, nr++) {
296     /* just show one pass of each kind */
297     if (BLI_findstring_ptr(&added_passes, rpass->name, offsetof(LinkData, data))) {
298       continue;
299     }
300     BLI_addtail(&added_passes, BLI_genericNodeN(rpass->name));
301 
302     uiDefButS(block,
303               UI_BTYPE_BUT_MENU,
304               B_NOP,
305               IFACE_(rpass->name),
306               0,
307               0,
308               UI_UNIT_X * 5,
309               UI_UNIT_X,
310               &iuser->pass,
311               (float)nr,
312               0.0,
313               0,
314               -1,
315               "");
316   }
317 
318   BLI_freelistN(&added_passes);
319 
320   BKE_image_release_renderresult(scene, image);
321 }
322 
323 /**************************** view menus *****************************/
ui_imageuser_view_menu_rr(bContext * UNUSED (C),uiLayout * layout,void * rnd_pt)324 static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
325 {
326   struct ImageUI_Data *rnd_data = rnd_pt;
327   uiBlock *block = uiLayoutGetBlock(layout);
328   Image *image = rnd_data->image;
329   ImageUser *iuser = rnd_data->iuser;
330   RenderResult *rr;
331   RenderView *rview;
332   int nr;
333   Scene *scene = iuser->scene;
334 
335   /* may have been freed since drawing */
336   rr = BKE_image_acquire_renderresult(scene, image);
337   if (UNLIKELY(rr == NULL)) {
338     return;
339   }
340 
341   UI_block_layout_set_current(block, layout);
342   uiLayoutColumn(layout, false);
343 
344   uiDefBut(block,
345            UI_BTYPE_LABEL,
346            0,
347            IFACE_("View"),
348            0,
349            0,
350            UI_UNIT_X * 5,
351            UI_UNIT_Y,
352            NULL,
353            0.0,
354            0.0,
355            0,
356            0,
357            "");
358 
359   uiItemS(layout);
360 
361   nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1;
362   for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) {
363     uiDefButS(block,
364               UI_BTYPE_BUT_MENU,
365               B_NOP,
366               IFACE_(rview->name),
367               0,
368               0,
369               UI_UNIT_X * 5,
370               UI_UNIT_X,
371               &iuser->view,
372               (float)nr,
373               0.0,
374               0,
375               -1,
376               "");
377   }
378 
379   BKE_image_release_renderresult(scene, image);
380 }
381 
ui_imageuser_view_menu_multiview(bContext * UNUSED (C),uiLayout * layout,void * rnd_pt)382 static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
383 {
384   struct ImageUI_Data *rnd_data = rnd_pt;
385   uiBlock *block = uiLayoutGetBlock(layout);
386   Image *image = rnd_data->image;
387   ImageUser *iuser = rnd_data->iuser;
388   int nr;
389   ImageView *iv;
390 
391   UI_block_layout_set_current(block, layout);
392   uiLayoutColumn(layout, false);
393 
394   uiDefBut(block,
395            UI_BTYPE_LABEL,
396            0,
397            IFACE_("View"),
398            0,
399            0,
400            UI_UNIT_X * 5,
401            UI_UNIT_Y,
402            NULL,
403            0.0,
404            0.0,
405            0,
406            0,
407            "");
408 
409   uiItemS(layout);
410 
411   nr = BLI_listbase_count(&image->views) - 1;
412   for (iv = image->views.last; iv; iv = iv->prev, nr--) {
413     uiDefButS(block,
414               UI_BTYPE_BUT_MENU,
415               B_NOP,
416               IFACE_(iv->name),
417               0,
418               0,
419               UI_UNIT_X * 5,
420               UI_UNIT_X,
421               &iuser->view,
422               (float)nr,
423               0.0,
424               0,
425               -1,
426               "");
427   }
428 }
429 
430 /* 5 layer button callbacks... */
image_multi_cb(bContext * C,void * rnd_pt,void * rr_v)431 static void image_multi_cb(bContext *C, void *rnd_pt, void *rr_v)
432 {
433   struct ImageUI_Data *rnd_data = rnd_pt;
434   ImageUser *iuser = rnd_data->iuser;
435 
436   BKE_image_multilayer_index(rr_v, iuser);
437   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
438 }
439 
ui_imageuser_layer_menu_step(bContext * C,int direction,void * rnd_pt)440 static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_pt)
441 {
442   Scene *scene = CTX_data_scene(C);
443   struct ImageUI_Data *rnd_data = rnd_pt;
444   Image *image = rnd_data->image;
445   ImageUser *iuser = rnd_data->iuser;
446   RenderResult *rr;
447   bool changed = false;
448 
449   rr = BKE_image_acquire_renderresult(scene, image);
450   if (UNLIKELY(rr == NULL)) {
451     return false;
452   }
453 
454   if (direction == -1) {
455     if (iuser->layer > 0) {
456       iuser->layer--;
457       changed = true;
458     }
459   }
460   else if (direction == 1) {
461     int tot = BLI_listbase_count(&rr->layers);
462 
463     if (RE_HasCombinedLayer(rr)) {
464       tot++; /* fake compo/sequencer layer */
465     }
466 
467     if (iuser->layer < tot - 1) {
468       iuser->layer++;
469       changed = true;
470     }
471   }
472   else {
473     BLI_assert(0);
474   }
475 
476   BKE_image_release_renderresult(scene, image);
477 
478   if (changed) {
479     BKE_image_multilayer_index(rr, iuser);
480     WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
481   }
482 
483   return changed;
484 }
485 
ui_imageuser_pass_menu_step(bContext * C,int direction,void * rnd_pt)486 static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt)
487 {
488   Scene *scene = CTX_data_scene(C);
489   struct ImageUI_Data *rnd_data = rnd_pt;
490   Image *image = rnd_data->image;
491   ImageUser *iuser = rnd_data->iuser;
492   RenderResult *rr;
493   bool changed = false;
494   int layer = iuser->layer;
495   RenderLayer *rl;
496   RenderPass *rpass;
497 
498   rr = BKE_image_acquire_renderresult(scene, image);
499   if (UNLIKELY(rr == NULL)) {
500     BKE_image_release_renderresult(scene, image);
501     return false;
502   }
503 
504   if (RE_HasCombinedLayer(rr)) {
505     layer -= 1;
506   }
507 
508   rl = BLI_findlink(&rr->layers, layer);
509   if (rl == NULL) {
510     BKE_image_release_renderresult(scene, image);
511     return false;
512   }
513 
514   rpass = BLI_findlink(&rl->passes, iuser->pass);
515   if (rpass == NULL) {
516     BKE_image_release_renderresult(scene, image);
517     return false;
518   }
519 
520   /* note, this looks reversed, but matches menu direction */
521   if (direction == -1) {
522     RenderPass *rp;
523     int rp_index = iuser->pass + 1;
524 
525     for (rp = rpass->next; rp; rp = rp->next, rp_index++) {
526       if (!STREQ(rp->name, rpass->name)) {
527         iuser->pass = rp_index;
528         changed = true;
529         break;
530       }
531     }
532   }
533   else if (direction == 1) {
534     RenderPass *rp;
535     int rp_index = 0;
536 
537     if (iuser->pass == 0) {
538       BKE_image_release_renderresult(scene, image);
539       return false;
540     }
541 
542     for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) {
543       if (STREQ(rp->name, rpass->name)) {
544         iuser->pass = rp_index - 1;
545         changed = true;
546         break;
547       }
548     }
549   }
550   else {
551     BLI_assert(0);
552   }
553 
554   BKE_image_release_renderresult(scene, image);
555 
556   if (changed) {
557     BKE_image_multilayer_index(rr, iuser);
558     WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
559   }
560 
561   return changed;
562 }
563 
564 /* 5 view button callbacks... */
image_multiview_cb(bContext * C,void * rnd_pt,void * UNUSED (arg_v))565 static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v))
566 {
567   struct ImageUI_Data *rnd_data = rnd_pt;
568   Image *ima = rnd_data->image;
569   ImageUser *iuser = rnd_data->iuser;
570 
571   BKE_image_multiview_index(ima, iuser);
572   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
573 }
574 
uiblock_layer_pass_buttons(uiLayout * layout,Image * image,RenderResult * rr,ImageUser * iuser,int w,const short * render_slot)575 static void uiblock_layer_pass_buttons(uiLayout *layout,
576                                        Image *image,
577                                        RenderResult *rr,
578                                        ImageUser *iuser,
579                                        int w,
580                                        const short *render_slot)
581 {
582   struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL;
583   uiBlock *block = uiLayoutGetBlock(layout);
584   uiBut *but;
585   RenderLayer *rl = NULL;
586   int wmenu1, wmenu2, wmenu3, wmenu4;
587   const char *fake_name;
588   const char *display_name = "";
589   const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0;
590 
591   if (iuser->scene == NULL) {
592     return;
593   }
594 
595   uiLayoutRow(layout, true);
596 
597   /* layer menu is 1/3 larger than pass */
598   wmenu1 = (2 * w) / 5;
599   wmenu2 = (3 * w) / 5;
600   wmenu3 = (3 * w) / 6;
601   wmenu4 = (3 * w) / 6;
602 
603   rnd_pt_local.image = image;
604   rnd_pt_local.iuser = iuser;
605   rnd_pt_local.rpass_index = 0;
606 
607   /* menu buts */
608   if (render_slot) {
609     char str[64];
610     RenderSlot *slot = BKE_image_get_renderslot(image, *render_slot);
611     if (slot && slot->name[0] != '\0') {
612       BLI_strncpy(str, slot->name, sizeof(str));
613     }
614     else {
615       BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
616     }
617 
618     rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
619     but = uiDefMenuBut(
620         block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
621     UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step);
622     UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
623     UI_but_type_set_menu_from_pulldown(but);
624     rnd_pt = NULL;
625   }
626 
627   if (rr) {
628     RenderPass *rpass;
629     RenderView *rview;
630     int rpass_index;
631 
632     /* layer */
633     fake_name = ui_imageuser_layer_fake_name(rr);
634     rpass_index = iuser->layer - (fake_name ? 1 : 0);
635     rl = BLI_findlink(&rr->layers, rpass_index);
636     rnd_pt_local.rpass_index = rpass_index;
637 
638     if (RE_layers_have_name(rr)) {
639       display_name = rl ? rl->name : (fake_name ? fake_name : "");
640       rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
641       but = uiDefMenuBut(block,
642                          ui_imageuser_layer_menu,
643                          rnd_pt,
644                          display_name,
645                          0,
646                          0,
647                          wmenu2,
648                          UI_UNIT_Y,
649                          TIP_("Select Layer"));
650       UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step);
651       UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
652       UI_but_type_set_menu_from_pulldown(but);
653       rnd_pt = NULL;
654     }
655 
656     /* pass */
657     rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL);
658 
659     if (rl && RE_passes_have_name(rl)) {
660       display_name = rpass ? rpass->name : "";
661       rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
662       but = uiDefMenuBut(block,
663                          ui_imageuser_pass_menu,
664                          rnd_pt,
665                          IFACE_(display_name),
666                          0,
667                          0,
668                          wmenu3,
669                          UI_UNIT_Y,
670                          TIP_("Select Pass"));
671       UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step);
672       UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
673       UI_but_type_set_menu_from_pulldown(but);
674       rnd_pt = NULL;
675     }
676 
677     /* view */
678     if (BLI_listbase_count_at_most(&rr->views, 2) > 1 &&
679         ((!show_stereo) || (!RE_RenderResult_is_stereo(rr)))) {
680       rview = BLI_findlink(&rr->views, iuser->view);
681       display_name = rview ? rview->name : "";
682 
683       rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
684       but = uiDefMenuBut(block,
685                          ui_imageuser_view_menu_rr,
686                          rnd_pt,
687                          display_name,
688                          0,
689                          0,
690                          wmenu4,
691                          UI_UNIT_Y,
692                          TIP_("Select View"));
693       UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
694       UI_but_type_set_menu_from_pulldown(but);
695       rnd_pt = NULL;
696     }
697   }
698 
699   /* stereo image */
700   else if ((BKE_image_is_stereo(image) && (!show_stereo)) ||
701            (BKE_image_is_multiview(image) && !BKE_image_is_stereo(image))) {
702     ImageView *iv;
703     int nr = 0;
704 
705     for (iv = image->views.first; iv; iv = iv->next) {
706       if (nr++ == iuser->view) {
707         display_name = iv->name;
708         break;
709       }
710     }
711 
712     rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
713     but = uiDefMenuBut(block,
714                        ui_imageuser_view_menu_multiview,
715                        rnd_pt,
716                        display_name,
717                        0,
718                        0,
719                        wmenu1,
720                        UI_UNIT_Y,
721                        TIP_("Select View"));
722     UI_but_funcN_set(but, image_multiview_cb, rnd_pt, NULL);
723     UI_but_type_set_menu_from_pulldown(but);
724     rnd_pt = NULL;
725   }
726 }
727 
728 typedef struct RNAUpdateCb {
729   PointerRNA ptr;
730   PropertyRNA *prop;
731   ImageUser *iuser;
732 } RNAUpdateCb;
733 
rna_update_cb(bContext * C,void * arg_cb,void * UNUSED (arg))734 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
735 {
736   RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
737 
738   /* ideally this would be done by RNA itself, but there we have
739    * no image user available, so we just update this flag here */
740   cb->iuser->ok = 1;
741 
742   /* we call update here on the pointer property, this way the
743    * owner of the image pointer can still define its own update
744    * and notifier */
745   RNA_property_update(C, &cb->ptr, cb->prop);
746 }
747 
image_has_alpha(Image * ima,ImageUser * iuser)748 static bool image_has_alpha(Image *ima, ImageUser *iuser)
749 {
750   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
751   if (ibuf == NULL) {
752     return false;
753   }
754 
755   int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions);
756   char valid_channels = BKE_imtype_valid_channels(imtype, false);
757   bool has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0;
758 
759   BKE_image_release_ibuf(ima, ibuf, NULL);
760 
761   return has_alpha;
762 }
763 
uiTemplateImage(uiLayout * layout,bContext * C,PointerRNA * ptr,const char * propname,PointerRNA * userptr,bool compact,bool multiview)764 void uiTemplateImage(uiLayout *layout,
765                      bContext *C,
766                      PointerRNA *ptr,
767                      const char *propname,
768                      PointerRNA *userptr,
769                      bool compact,
770                      bool multiview)
771 {
772   if (!ptr->data) {
773     return;
774   }
775 
776   PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
777   if (!prop) {
778     printf(
779         "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
780     return;
781   }
782 
783   if (RNA_property_type(prop) != PROP_POINTER) {
784     printf("%s: expected pointer property for %s.%s\n",
785            __func__,
786            RNA_struct_identifier(ptr->type),
787            propname);
788     return;
789   }
790 
791   uiBlock *block = uiLayoutGetBlock(layout);
792 
793   PointerRNA imaptr = RNA_property_pointer_get(ptr, prop);
794   Image *ima = imaptr.data;
795   ImageUser *iuser = userptr->data;
796 
797   Scene *scene = CTX_data_scene(C);
798   BKE_image_user_frame_calc(ima, iuser, (int)scene->r.cfra);
799 
800   uiLayoutSetContextPointer(layout, "edit_image", &imaptr);
801   uiLayoutSetContextPointer(layout, "edit_image_user", userptr);
802 
803   SpaceImage *space_image = CTX_wm_space_image(C);
804   if (!compact && (space_image == NULL || iuser != &space_image->iuser)) {
805     uiTemplateID(layout,
806                  C,
807                  ptr,
808                  propname,
809                  ima ? NULL : "IMAGE_OT_new",
810                  "IMAGE_OT_open",
811                  NULL,
812                  UI_TEMPLATE_ID_FILTER_ALL,
813                  false,
814                  NULL);
815 
816     if (ima != NULL) {
817       uiItemS(layout);
818     }
819   }
820 
821   if (ima == NULL) {
822     return;
823   }
824 
825   if (ima->source == IMA_SRC_VIEWER) {
826     /* Viewer images. */
827     uiTemplateImageInfo(layout, C, ima, iuser);
828 
829     if (ima->type == IMA_TYPE_COMPOSITE) {
830     }
831     else if (ima->type == IMA_TYPE_R_RESULT) {
832       /* browse layer/passes */
833       RenderResult *rr;
834       const float dpi_fac = UI_DPI_FAC;
835       const int menus_width = 230 * dpi_fac;
836 
837       /* use BKE_image_acquire_renderresult  so we get the correct slot in the menu */
838       rr = BKE_image_acquire_renderresult(scene, ima);
839       uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
840       BKE_image_release_renderresult(scene, ima);
841     }
842 
843     return;
844   }
845 
846   /* Set custom callback for property updates. */
847   RNAUpdateCb *cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
848   cb->ptr = *ptr;
849   cb->prop = prop;
850   cb->iuser = iuser;
851   UI_block_funcN_set(block, rna_update_cb, cb, NULL);
852 
853   /* Disable editing if image was modified, to avoid losing changes. */
854   const bool is_dirty = BKE_image_is_dirty(ima);
855   if (is_dirty) {
856     uiLayout *row = uiLayoutRow(layout, true);
857     uiItemO(row, IFACE_("Save"), ICON_NONE, "image.save");
858     uiItemO(row, IFACE_("Discard"), ICON_NONE, "image.reload");
859     uiItemS(layout);
860   }
861 
862   layout = uiLayoutColumn(layout, false);
863   uiLayoutSetEnabled(layout, !is_dirty);
864   uiLayoutSetPropDecorate(layout, false);
865 
866   /* Image source */
867   {
868     uiLayout *col = uiLayoutColumn(layout, false);
869     uiLayoutSetPropSep(col, true);
870     uiItemR(col, &imaptr, "source", 0, NULL, ICON_NONE);
871   }
872 
873   /* Filepath */
874   const bool is_packed = BKE_image_has_packedfile(ima);
875   const bool no_filepath = is_packed && !BKE_image_has_filepath(ima);
876 
877   if ((ima->source != IMA_SRC_GENERATED) && !no_filepath) {
878     uiItemS(layout);
879 
880     uiLayout *row = uiLayoutRow(layout, true);
881     if (is_packed) {
882       uiItemO(row, "", ICON_PACKAGE, "image.unpack");
883     }
884     else {
885       uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
886     }
887 
888     row = uiLayoutRow(row, true);
889     uiLayoutSetEnabled(row, is_packed == false);
890     uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
891     uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
892   }
893 
894   /* Image layers and Info */
895   if (ima->source == IMA_SRC_GENERATED) {
896     uiItemS(layout);
897 
898     /* Generated */
899     uiLayout *col = uiLayoutColumn(layout, false);
900     uiLayoutSetPropSep(col, true);
901 
902     uiLayout *sub = uiLayoutColumn(col, true);
903     uiItemR(sub, &imaptr, "generated_width", 0, "X", ICON_NONE);
904     uiItemR(sub, &imaptr, "generated_height", 0, "Y", ICON_NONE);
905 
906     uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE);
907 
908     uiItemS(col);
909 
910     uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, IFACE_("Type"), ICON_NONE);
911     if (ima->gen_type == IMA_GENTYPE_BLANK) {
912       uiItemR(col, &imaptr, "generated_color", 0, NULL, ICON_NONE);
913     }
914   }
915   else if (compact == 0) {
916     uiTemplateImageInfo(layout, C, ima, iuser);
917   }
918   if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
919     uiItemS(layout);
920 
921     const float dpi_fac = UI_DPI_FAC;
922     uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
923   }
924 
925   if (BKE_image_is_animated(ima)) {
926     /* Animation */
927     uiItemS(layout);
928 
929     uiLayout *col = uiLayoutColumn(layout, true);
930     uiLayoutSetPropSep(col, true);
931 
932     uiLayout *sub = uiLayoutColumn(col, true);
933     uiLayout *row = uiLayoutRow(sub, true);
934     uiItemR(row, userptr, "frame_duration", 0, IFACE_("Frames"), ICON_NONE);
935     uiItemO(row, "", ICON_FILE_REFRESH, "IMAGE_OT_match_movie_length");
936 
937     uiItemR(sub, userptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
938     uiItemR(sub, userptr, "frame_offset", 0, NULL, ICON_NONE);
939 
940     uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE);
941     uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE);
942 
943     if (ima->source == IMA_SRC_MOVIE && compact == 0) {
944       uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
945     }
946   }
947 
948   /* Multiview */
949   if (multiview && compact == 0) {
950     if ((scene->r.scemode & R_MULTIVIEW) != 0) {
951       uiItemS(layout);
952 
953       uiLayout *col = uiLayoutColumn(layout, false);
954       uiLayoutSetPropSep(col, true);
955       uiItemR(col, &imaptr, "use_multiview", 0, NULL, ICON_NONE);
956 
957       if (RNA_boolean_get(&imaptr, "use_multiview")) {
958         uiTemplateImageViews(layout, &imaptr);
959       }
960     }
961   }
962 
963   /* Colorspace and alpha */
964   {
965     uiItemS(layout);
966 
967     uiLayout *col = uiLayoutColumn(layout, false);
968     uiLayoutSetPropSep(col, true);
969     uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings");
970 
971     if (compact == 0) {
972       if (ima->source != IMA_SRC_GENERATED) {
973         if (image_has_alpha(ima, iuser)) {
974           uiLayout *sub = uiLayoutColumn(col, false);
975           uiItemR(sub, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
976 
977           bool is_data = IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name);
978           uiLayoutSetActive(sub, !is_data);
979         }
980 
981         if (ima && iuser) {
982           void *lock;
983           ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
984 
985           if (ibuf && ibuf->rect_float && (ibuf->flags & IB_halffloat) == 0) {
986             uiItemR(col, &imaptr, "use_half_precision", 0, NULL, ICON_NONE);
987           }
988           BKE_image_release_ibuf(ima, ibuf, lock);
989         }
990       }
991 
992       uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE);
993     }
994   }
995 
996   UI_block_funcN_set(block, NULL, NULL, NULL);
997 }
998 
uiTemplateImageSettings(uiLayout * layout,PointerRNA * imfptr,bool color_management)999 void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management)
1000 {
1001   ImageFormatData *imf = imfptr->data;
1002   ID *id = imfptr->owner_id;
1003   PointerRNA display_settings_ptr;
1004   PropertyRNA *prop;
1005   const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
1006   /* some settings depend on this being a scene that's rendered */
1007   const bool is_render_out = (id && GS(id->name) == ID_SCE);
1008 
1009   uiLayout *col;
1010   bool show_preview = false;
1011 
1012   col = uiLayoutColumn(layout, false);
1013 
1014   uiLayoutSetPropSep(col, true);
1015   uiLayoutSetPropDecorate(col, false);
1016 
1017   uiItemR(col, imfptr, "file_format", 0, NULL, ICON_NONE);
1018   uiItemR(
1019       uiLayoutRow(col, true), imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE);
1020 
1021   /* only display depth setting if multiple depths can be used */
1022   if ((ELEM(depth_ok,
1023             R_IMF_CHAN_DEPTH_1,
1024             R_IMF_CHAN_DEPTH_8,
1025             R_IMF_CHAN_DEPTH_10,
1026             R_IMF_CHAN_DEPTH_12,
1027             R_IMF_CHAN_DEPTH_16,
1028             R_IMF_CHAN_DEPTH_24,
1029             R_IMF_CHAN_DEPTH_32)) == 0) {
1030     uiItemR(uiLayoutRow(col, true), imfptr, "color_depth", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1031   }
1032 
1033   if (BKE_imtype_supports_quality(imf->imtype)) {
1034     uiItemR(col, imfptr, "quality", 0, NULL, ICON_NONE);
1035   }
1036 
1037   if (BKE_imtype_supports_compress(imf->imtype)) {
1038     uiItemR(col, imfptr, "compression", 0, NULL, ICON_NONE);
1039   }
1040 
1041   if (ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
1042     uiItemR(col, imfptr, "exr_codec", 0, NULL, ICON_NONE);
1043   }
1044 
1045   if (BKE_imtype_supports_zbuf(imf->imtype)) {
1046     uiItemR(col, imfptr, "use_zbuffer", 0, NULL, ICON_NONE);
1047   }
1048 
1049   if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
1050     show_preview = true;
1051     uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE);
1052   }
1053 
1054   if (imf->imtype == R_IMF_IMTYPE_JP2) {
1055     uiItemR(col, imfptr, "jpeg2k_codec", 0, NULL, ICON_NONE);
1056 
1057     uiItemR(col, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE);
1058     uiItemR(col, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE);
1059 
1060     uiItemR(col, imfptr, "use_jpeg2k_ycc", 0, NULL, ICON_NONE);
1061   }
1062 
1063   if (imf->imtype == R_IMF_IMTYPE_DPX) {
1064     uiItemR(col, imfptr, "use_cineon_log", 0, NULL, ICON_NONE);
1065   }
1066 
1067   if (imf->imtype == R_IMF_IMTYPE_CINEON) {
1068 #if 1
1069     uiItemL(col, IFACE_("Hard coded Non-Linear, Gamma:1.7"), ICON_NONE);
1070 #else
1071     uiItemR(col, imfptr, "use_cineon_log", 0, NULL, ICON_NONE);
1072     uiItemR(col, imfptr, "cineon_black", 0, NULL, ICON_NONE);
1073     uiItemR(col, imfptr, "cineon_white", 0, NULL, ICON_NONE);
1074     uiItemR(col, imfptr, "cineon_gamma", 0, NULL, ICON_NONE);
1075 #endif
1076   }
1077 
1078   if (imf->imtype == R_IMF_IMTYPE_TIFF) {
1079     uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE);
1080   }
1081 
1082   /* color management */
1083   if (color_management && (!BKE_imtype_requires_linear_float(imf->imtype) ||
1084                            (show_preview && imf->flag & R_IMF_FLAG_PREVIEW_JPG))) {
1085     prop = RNA_struct_find_property(imfptr, "display_settings");
1086     display_settings_ptr = RNA_property_pointer_get(imfptr, prop);
1087 
1088     col = uiLayoutColumn(layout, false);
1089     uiItemL(col, IFACE_("Color Management"), ICON_NONE);
1090 
1091     uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE);
1092 
1093     uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings");
1094   }
1095 }
1096 
uiTemplateImageStereo3d(uiLayout * layout,PointerRNA * stereo3d_format_ptr)1097 void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
1098 {
1099   Stereo3dFormat *stereo3d_format = stereo3d_format_ptr->data;
1100   uiLayout *col;
1101 
1102   col = uiLayoutColumn(layout, false);
1103   uiItemR(col, stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
1104 
1105   switch (stereo3d_format->display_mode) {
1106     case S3D_DISPLAY_ANAGLYPH: {
1107       uiItemR(col, stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
1108       break;
1109     }
1110     case S3D_DISPLAY_INTERLACE: {
1111       uiItemR(col, stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
1112       uiItemR(col, stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
1113       break;
1114     }
1115     case S3D_DISPLAY_SIDEBYSIDE: {
1116       uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
1117       ATTR_FALLTHROUGH;
1118     }
1119     case S3D_DISPLAY_TOPBOTTOM: {
1120       uiItemR(col, stereo3d_format_ptr, "use_squeezed_frame", 0, NULL, ICON_NONE);
1121       break;
1122     }
1123   }
1124 }
1125 
uiTemplateViewsFormat(uiLayout * layout,PointerRNA * ptr,PointerRNA * stereo3d_format_ptr)1126 static void uiTemplateViewsFormat(uiLayout *layout,
1127                                   PointerRNA *ptr,
1128                                   PointerRNA *stereo3d_format_ptr)
1129 {
1130   uiLayout *col;
1131 
1132   col = uiLayoutColumn(layout, false);
1133 
1134   uiLayoutSetPropSep(col, true);
1135   uiLayoutSetPropDecorate(col, false);
1136 
1137   uiItemR(col, ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1138 
1139   if (stereo3d_format_ptr && RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D) {
1140     uiTemplateImageStereo3d(col, stereo3d_format_ptr);
1141   }
1142 }
1143 
uiTemplateImageViews(uiLayout * layout,PointerRNA * imaptr)1144 void uiTemplateImageViews(uiLayout *layout, PointerRNA *imaptr)
1145 {
1146   Image *ima = imaptr->data;
1147 
1148   if (ima->type != IMA_TYPE_MULTILAYER) {
1149     PropertyRNA *prop;
1150     PointerRNA stereo3d_format_ptr;
1151 
1152     prop = RNA_struct_find_property(imaptr, "stereo_3d_format");
1153     stereo3d_format_ptr = RNA_property_pointer_get(imaptr, prop);
1154 
1155     uiTemplateViewsFormat(layout, imaptr, &stereo3d_format_ptr);
1156   }
1157   else {
1158     uiTemplateViewsFormat(layout, imaptr, NULL);
1159   }
1160 }
1161 
uiTemplateImageFormatViews(uiLayout * layout,PointerRNA * imfptr,PointerRNA * ptr)1162 void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
1163 {
1164   ImageFormatData *imf = imfptr->data;
1165 
1166   if (ptr != NULL) {
1167     uiItemR(layout, ptr, "use_multiview", 0, NULL, ICON_NONE);
1168     if (!RNA_boolean_get(ptr, "use_multiview")) {
1169       return;
1170     }
1171   }
1172 
1173   if (imf->imtype != R_IMF_IMTYPE_MULTILAYER) {
1174     PropertyRNA *prop;
1175     PointerRNA stereo3d_format_ptr;
1176 
1177     prop = RNA_struct_find_property(imfptr, "stereo_3d_format");
1178     stereo3d_format_ptr = RNA_property_pointer_get(imfptr, prop);
1179 
1180     uiTemplateViewsFormat(layout, imfptr, &stereo3d_format_ptr);
1181   }
1182   else {
1183     uiTemplateViewsFormat(layout, imfptr, NULL);
1184   }
1185 }
1186 
uiTemplateImageLayers(uiLayout * layout,bContext * C,Image * ima,ImageUser * iuser)1187 void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
1188 {
1189   Scene *scene = CTX_data_scene(C);
1190 
1191   /* render layers and passes */
1192   if (ima && iuser) {
1193     RenderResult *rr;
1194     const float dpi_fac = UI_DPI_FAC;
1195     const int menus_width = 160 * dpi_fac;
1196     const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT);
1197 
1198     /* use BKE_image_acquire_renderresult  so we get the correct slot in the menu */
1199     rr = BKE_image_acquire_renderresult(scene, ima);
1200     uiblock_layer_pass_buttons(
1201         layout, ima, rr, iuser, menus_width, is_render_result ? &ima->render_slot : NULL);
1202     BKE_image_release_renderresult(scene, ima);
1203   }
1204 }
1205 
uiTemplateImageInfo(uiLayout * layout,bContext * C,Image * ima,ImageUser * iuser)1206 void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
1207 {
1208   if (ima == NULL || iuser == NULL) {
1209     return;
1210   }
1211 
1212   /* Acquire image buffer. */
1213   void *lock;
1214   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
1215 
1216   uiLayout *col = uiLayoutColumn(layout, true);
1217   uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT);
1218 
1219   if (ibuf == NULL) {
1220     uiItemL(col, TIP_("Can't Load Image"), ICON_NONE);
1221   }
1222   else {
1223     char str[MAX_IMAGE_INFO_LEN] = {0};
1224     const int len = MAX_IMAGE_INFO_LEN;
1225     int ofs = 0;
1226 
1227     ofs += BLI_snprintf(str + ofs, len - ofs, TIP_("%d x %d, "), ibuf->x, ibuf->y);
1228 
1229     if (ibuf->rect_float) {
1230       if (ibuf->channels != 4) {
1231         ofs += BLI_snprintf(str + ofs, len - ofs, TIP_("%d float channel(s)"), ibuf->channels);
1232       }
1233       else if (ibuf->planes == R_IMF_PLANES_RGBA) {
1234         ofs += BLI_strncpy_rlen(str + ofs, TIP_(" RGBA float"), len - ofs);
1235       }
1236       else {
1237         ofs += BLI_strncpy_rlen(str + ofs, TIP_(" RGB float"), len - ofs);
1238       }
1239     }
1240     else {
1241       if (ibuf->planes == R_IMF_PLANES_RGBA) {
1242         ofs += BLI_strncpy_rlen(str + ofs, TIP_(" RGBA byte"), len - ofs);
1243       }
1244       else {
1245         ofs += BLI_strncpy_rlen(str + ofs, TIP_(" RGB byte"), len - ofs);
1246       }
1247     }
1248     if (ibuf->zbuf || ibuf->zbuf_float) {
1249       ofs += BLI_strncpy_rlen(str + ofs, TIP_(" + Z"), len - ofs);
1250     }
1251 
1252     uiItemL(col, str, ICON_NONE);
1253   }
1254 
1255   /* Frame number, even if we can't load the image. */
1256   if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
1257     /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
1258     Scene *scene = CTX_data_scene(C);
1259     const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL);
1260     char str[MAX_IMAGE_INFO_LEN];
1261     int duration = 0;
1262 
1263     if (ima->source == IMA_SRC_MOVIE && BKE_image_has_anim(ima)) {
1264       struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
1265       if (anim) {
1266         duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1267       }
1268     }
1269 
1270     if (duration > 0) {
1271       /* Movie duration */
1272       BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d / %d"), framenr, duration);
1273     }
1274     else if (ima->source == IMA_SRC_SEQUENCE && ibuf) {
1275       /* Image sequence frame number + filename */
1276       const char *filename = BLI_path_slash_rfind(ibuf->name);
1277       filename = (filename == NULL) ? ibuf->name : filename + 1;
1278       BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d: %s"), framenr, filename);
1279     }
1280     else {
1281       /* Frame number */
1282       BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d"), framenr);
1283     }
1284 
1285     uiItemL(col, str, ICON_NONE);
1286   }
1287 
1288   BKE_image_release_ibuf(ima, ibuf, lock);
1289 }
1290 
1291 #undef MAX_IMAGE_INFO_LEN
1292 
metadata_panel_context_poll(const bContext * C,PanelType * UNUSED (pt))1293 static bool metadata_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
1294 {
1295   SpaceImage *space_image = CTX_wm_space_image(C);
1296   return space_image != NULL && space_image->image != NULL;
1297 }
1298 
metadata_panel_context_draw(const bContext * C,Panel * panel)1299 static void metadata_panel_context_draw(const bContext *C, Panel *panel)
1300 {
1301   void *lock;
1302   SpaceImage *space_image = CTX_wm_space_image(C);
1303   Image *image = space_image->image;
1304   ImBuf *ibuf = BKE_image_acquire_ibuf(image, &space_image->iuser, &lock);
1305   if (ibuf != NULL) {
1306     ED_region_image_metadata_panel_draw(ibuf, panel->layout);
1307   }
1308   BKE_image_release_ibuf(image, ibuf, lock);
1309 }
1310 
image_buttons_register(ARegionType * art)1311 void image_buttons_register(ARegionType *art)
1312 {
1313   PanelType *pt;
1314 
1315   pt = MEM_callocN(sizeof(PanelType), "spacetype image panel metadata");
1316   strcpy(pt->idname, "IMAGE_PT_metadata");
1317   strcpy(pt->label, N_("Metadata"));
1318   strcpy(pt->category, "Image");
1319   strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1320   pt->order = 10;
1321   pt->poll = metadata_panel_context_poll;
1322   pt->draw = metadata_panel_context_draw;
1323   pt->flag |= PNL_DEFAULT_CLOSED;
1324   BLI_addtail(&art->paneltypes, pt);
1325 }
1326