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