Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_buttons / buttons_texture.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_buttons/buttons_texture.c
27  *  \ingroup spbuttons
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39
40 #include "BLT_translation.h"
41
42 #include "DNA_brush_types.h"
43 #include "DNA_ID.h"
44 #include "DNA_lamp_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_node_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_object_force_types.h"
49 #include "DNA_particle_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_world_types.h"
54 #include "DNA_linestyle_types.h"
55
56 #include "BKE_context.h"
57 #include "BKE_layer.h"
58 #include "BKE_linestyle.h"
59 #include "BKE_material.h"
60 #include "BKE_modifier.h"
61 #include "BKE_node.h"
62 #include "BKE_paint.h"
63 #include "BKE_particle.h"
64 #include "BKE_scene.h"
65 #ifdef WITH_FREESTYLE
66 #  include "BKE_freestyle.h"
67 #endif
68
69 #include "RNA_access.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73
74 #include "ED_buttons.h"
75 #include "ED_node.h"
76 #include "ED_screen.h"
77
78 #include "../interface/interface_intern.h"
79
80 #include "buttons_intern.h" // own include
81
82 /****************** "Old Shading" Texture Context ****************/
83
84 bool ED_texture_context_check_world(const bContext *C)
85 {
86         Scene *scene = CTX_data_scene(C);
87         return (scene && scene->world);
88 }
89
90 bool ED_texture_context_check_material(const bContext *C)
91 {
92         Object *ob = CTX_data_active_object(C);
93         return (ob && (ob->totcol != 0));
94 }
95
96 bool ED_texture_context_check_lamp(const bContext *C)
97 {
98         Object *ob = CTX_data_active_object(C);
99         return (ob && (ob->type == OB_LAMP));
100 }
101
102 bool ED_texture_context_check_particles(const bContext *C)
103 {
104         Object *ob = CTX_data_active_object(C);
105         return (ob && ob->particlesystem.first);
106 }
107
108 bool ED_texture_context_check_linestyle(const bContext *C)
109 {
110 #ifdef WITH_FREESTYLE
111         Scene *scene = CTX_data_scene(C);
112         ViewLayer *active_view_layer;
113         FreestyleConfig *config;
114         FreestyleLineSet *lineset;
115         FreestyleLineStyle *linestyle;
116
117         if (scene && (scene->r.mode & R_EDGE_FRS)) {
118                 active_view_layer = BLI_findlink(&scene->view_layers, scene->active_view_layer);
119                 config = &active_view_layer->freestyle_config;
120                 if (config->mode == FREESTYLE_CONTROL_EDITOR_MODE) {
121                         lineset = BKE_freestyle_lineset_get_active(config);
122                         if (lineset) {
123                                 linestyle = lineset->linestyle;
124                                 return linestyle && (linestyle->flag & LS_TEXTURE);
125                         }
126                 }
127         }
128 #else
129         (void)C;
130 #endif
131         return false;
132 }
133
134 static void texture_context_check_modifier_foreach(void *userData, Object *UNUSED(ob), ModifierData *UNUSED(md),
135                                                    const char *UNUSED(propname))
136 {
137         *((bool *)userData) = true;
138 }
139
140 bool ED_texture_context_check_others(const bContext *C)
141 {
142         /* We cannot rely on sbuts->texuser here, as it is NULL when in "old" tex handling, non-OTHERS tex context. */
143         Object *ob = CTX_data_active_object(C);
144
145         /* object */
146         if (ob) {
147                 /* Tex force field. */
148                 if (ob->pd && ob->pd->forcefield == PFIELD_TEXTURE) {
149                         return true;
150                 }
151
152                 /* modifiers */
153                 {
154                         bool check = false;
155                         modifiers_foreachTexLink(ob, texture_context_check_modifier_foreach, &check);
156                         if (check) {
157                                 return true;
158                         }
159                 }
160         }
161
162         /* brush */
163         if (BKE_paint_brush(BKE_paint_get_active_from_context(C))) {
164                 return true;
165         }
166
167         return false;
168 }
169
170 static void set_texture_context(const bContext *C, SpaceButs *sbuts)
171 {
172         Scene *scene = CTX_data_scene(C);
173
174         if (BKE_scene_use_new_shading_nodes(scene)) {
175                 return;  /* No texture context in new shading mode */
176         }
177
178         {
179                 bool valid_world = ED_texture_context_check_world(C);
180                 bool valid_material = ED_texture_context_check_material(C);
181                 bool valid_lamp = ED_texture_context_check_lamp(C);
182                 bool valid_particles = ED_texture_context_check_particles(C);
183                 bool valid_linestyle = ED_texture_context_check_linestyle(C);
184                 bool valid_others = ED_texture_context_check_others(C);
185
186                 /* this is similar to direct user action, no need to keep "better" ctxt in _prev */
187                 if ((sbuts->mainb == BCONTEXT_WORLD) && valid_world) {
188                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_WORLD;
189                 }
190                 else if ((sbuts->mainb == BCONTEXT_MATERIAL) && valid_material) {
191                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_MATERIAL;
192                 }
193                 else if ((sbuts->mainb == BCONTEXT_DATA) && valid_lamp) {
194                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LAMP;
195                 }
196                 else if ((sbuts->mainb == BCONTEXT_PARTICLE) && valid_particles) {
197                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_PARTICLES;
198                 }
199                 else if ((sbuts->mainb == BCONTEXT_VIEW_LAYER) && valid_linestyle) {
200                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LINESTYLE;
201                 }
202                 else if ((ELEM(sbuts->mainb, BCONTEXT_MODIFIER, BCONTEXT_PHYSICS)) && valid_others) {
203                         sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_OTHER;
204                 }
205                 /* Else, try to revive a previous "better" ctxt... */
206                 else if ((sbuts->texture_context_prev != sbuts->texture_context) &&
207                          (((sbuts->texture_context_prev == SB_TEXC_WORLD) && valid_world) ||
208                           ((sbuts->texture_context_prev == SB_TEXC_MATERIAL) && valid_material) ||
209                           ((sbuts->texture_context_prev == SB_TEXC_LAMP) && valid_lamp) ||
210                           ((sbuts->texture_context_prev == SB_TEXC_PARTICLES) && valid_particles) ||
211                           ((sbuts->texture_context_prev == SB_TEXC_LINESTYLE) && valid_linestyle) ||
212                           ((sbuts->texture_context_prev == SB_TEXC_OTHER) && valid_others)))
213                 {
214                         sbuts->texture_context = sbuts->texture_context_prev;
215                 }
216                 /* Else, just be sure that current context is valid! */
217                 else if (((sbuts->texture_context == SB_TEXC_WORLD) && !valid_world) ||
218                          ((sbuts->texture_context == SB_TEXC_MATERIAL) && !valid_material) ||
219                          ((sbuts->texture_context == SB_TEXC_LAMP) && !valid_lamp) ||
220                          ((sbuts->texture_context == SB_TEXC_PARTICLES) && !valid_particles) ||
221                          ((sbuts->texture_context == SB_TEXC_LINESTYLE) && !valid_linestyle) ||
222                          ((sbuts->texture_context == SB_TEXC_OTHER) && !valid_others))
223                 {
224                         /* this is default fallback, do keep "better" ctxt in _prev */
225                         sbuts->texture_context_prev = sbuts->texture_context;
226                         if (valid_material) {
227                                 sbuts->texture_context = SB_TEXC_MATERIAL;
228                         }
229                         else if (valid_lamp) {
230                                 sbuts->texture_context = SB_TEXC_LAMP;
231                         }
232                         else if (valid_particles) {
233                                 sbuts->texture_context = SB_TEXC_PARTICLES;
234                         }
235                         else if (valid_linestyle) {
236                                 sbuts->texture_context = SB_TEXC_LINESTYLE;
237                         }
238                         else if (valid_world) {
239                                 sbuts->texture_context = SB_TEXC_WORLD;
240                         }
241                         else if (valid_others) {
242                                 sbuts->texture_context = SB_TEXC_OTHER;
243                         }
244                 }
245         }
246 }
247
248 /************************* Texture User **************************/
249
250 static void buttons_texture_user_property_add(ListBase *users, ID *id, 
251                                               PointerRNA ptr, PropertyRNA *prop,
252                                               const char *category, int icon, const char *name)
253 {
254         ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
255
256         user->id = id;
257         user->ptr = ptr;
258         user->prop = prop;
259         user->category = category;
260         user->icon = icon;
261         user->name = name;
262         user->index = BLI_listbase_count(users);
263
264         BLI_addtail(users, user);
265 }
266
267 static void buttons_texture_user_node_add(ListBase *users, ID *id, 
268                                           bNodeTree *ntree, bNode *node,
269                                           const char *category, int icon, const char *name)
270 {
271         ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
272
273         user->id = id;
274         user->ntree = ntree;
275         user->node = node;
276         user->category = category;
277         user->icon = icon;
278         user->name = name;
279         user->index = BLI_listbase_count(users);
280
281         BLI_addtail(users, user);
282 }
283
284 static void buttons_texture_users_find_nodetree(ListBase *users, ID *id,
285                                                 bNodeTree *ntree, const char *category)
286 {
287         bNode *node;
288
289         if (ntree) {
290                 for (node = ntree->nodes.first; node; node = node->next) {
291                         if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
292                                 PointerRNA ptr;
293                                 /* PropertyRNA *prop; */ /* UNUSED */
294                                 
295                                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
296                                 /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */
297                                 
298                                 buttons_texture_user_node_add(users, id, ntree, node,
299                                                               category, RNA_struct_ui_icon(ptr.type), node->name);
300                         }
301                         else if (node->type == NODE_GROUP && node->id) {
302                                 buttons_texture_users_find_nodetree(users, id, (bNodeTree *)node->id, category);
303                         }
304                 }
305         }
306 }
307
308 static void buttons_texture_modifier_foreach(void *userData, Object *ob, ModifierData *md, const char *propname)
309 {
310         PointerRNA ptr;
311         PropertyRNA *prop;
312         ListBase *users = userData;
313
314         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
315         prop = RNA_struct_find_property(&ptr, propname);
316
317         buttons_texture_user_property_add(users, &ob->id, ptr, prop,
318                                           N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
319 }
320
321 static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
322 {
323         Scene *scene = NULL;
324         Object *ob = NULL;
325         Material *ma = NULL;
326         Lamp *la = NULL;
327         World *wrld = NULL;
328         WorkSpace *workspace = NULL;
329         FreestyleLineStyle *linestyle = NULL;
330         Brush *brush = NULL;
331         ID *pinid = sbuts->pinid;
332         bool limited_mode = (sbuts->flag & SB_TEX_USER_LIMITED) != 0;
333
334         /* get data from context */
335         if (pinid) {
336                 if (GS(pinid->name) == ID_SCE)
337                         scene = (Scene *)pinid;
338                 else if (GS(pinid->name) == ID_OB)
339                         ob = (Object *)pinid;
340                 else if (GS(pinid->name) == ID_LA)
341                         la = (Lamp *)pinid;
342                 else if (GS(pinid->name) == ID_WO)
343                         wrld = (World *)pinid;
344                 else if (GS(pinid->name) == ID_MA)
345                         ma = (Material *)pinid;
346                 else if (GS(pinid->name) == ID_BR)
347                         brush = (Brush *)pinid;
348                 else if (GS(pinid->name) == ID_LS)
349                         linestyle = (FreestyleLineStyle *)pinid;
350                 else if (GS(pinid->name) == ID_WS)
351                         workspace = (WorkSpace *)workspace;
352         }
353
354         if (!scene) {
355                 scene = CTX_data_scene(C);
356         }
357
358         const ID_Type id_type = pinid != NULL ? GS(pinid->name) : -1;
359         if (!pinid || ELEM(id_type, ID_SCE, ID_WS)) {
360                 brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
361
362                 if (workspace == NULL) {
363                         wrld = scene->world;
364                         linestyle = BKE_linestyle_active_from_scene(scene);
365                         workspace = CTX_wm_workspace(C);
366                 }
367
368                 ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace);
369                 ob = OBACT(view_layer);
370         }
371
372         if (ob && ob->type == OB_LAMP && !la)
373                 la = ob->data;
374         if (ob && !ma)
375                 ma = give_current_material(ob, ob->actcol);
376
377         /* fill users */
378         BLI_listbase_clear(users);
379
380         if (ma && !limited_mode)
381                 buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, N_("Material"));
382         if (la && !limited_mode)
383                 buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, N_("Lamp"));
384         if (wrld && !limited_mode)
385                 buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, N_("World"));
386         if (linestyle && !limited_mode)
387                 buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, N_("Line Style"));
388
389         if (ob) {
390                 ParticleSystem *psys = psys_get_current(ob);
391                 MTex *mtex;
392                 int a;
393
394                 /* modifiers */
395                 modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
396
397                 /* particle systems */
398                 if (psys && !limited_mode) {
399                         for (a = 0; a < MAX_MTEX; a++) {
400                                 mtex = psys->part->mtex[a];
401
402                                 if (mtex) {
403                                         PointerRNA ptr;
404                                         PropertyRNA *prop;
405
406                                         RNA_pointer_create(&psys->part->id, &RNA_ParticleSettingsTextureSlot, mtex, &ptr);
407                                         prop = RNA_struct_find_property(&ptr, "texture");
408
409                                         buttons_texture_user_property_add(users, &psys->part->id, ptr, prop, N_("Particles"),
410                                                                           RNA_struct_ui_icon(&RNA_ParticleSettings), psys->name);
411                                 }
412                         }
413                 }
414
415                 /* field */
416                 if (ob->pd && ob->pd->forcefield == PFIELD_TEXTURE) {
417                         PointerRNA ptr;
418                         PropertyRNA *prop;
419
420                         RNA_pointer_create(&ob->id, &RNA_FieldSettings, ob->pd, &ptr);
421                         prop = RNA_struct_find_property(&ptr, "texture");
422
423                         buttons_texture_user_property_add(users, &ob->id, ptr, prop,
424                                                           N_("Fields"), ICON_FORCE_TEXTURE, IFACE_("Texture Field"));
425                 }
426         }
427
428         /* brush */
429         if (brush) {
430                 PointerRNA ptr;
431                 PropertyRNA *prop;
432
433                 /* texture */
434                 RNA_pointer_create(&brush->id, &RNA_BrushTextureSlot, &brush->mtex, &ptr);
435                 prop = RNA_struct_find_property(&ptr, "texture");
436
437                 buttons_texture_user_property_add(users, &brush->id, ptr, prop,
438                                                   N_("Brush"), ICON_BRUSH_DATA, IFACE_("Brush"));
439
440                 /* mask texture */
441                 RNA_pointer_create(&brush->id, &RNA_BrushTextureSlot, &brush->mask_mtex, &ptr);
442                 prop = RNA_struct_find_property(&ptr, "texture");
443
444                 buttons_texture_user_property_add(users, &brush->id, ptr, prop,
445                                                   N_("Brush"), ICON_BRUSH_DATA, IFACE_("Brush Mask"));
446         }
447 }
448
449 void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
450 {
451         /* gather available texture users in context. runs on every draw of
452          * properties editor, before the buttons are created. */
453         ButsContextTexture *ct = sbuts->texuser;
454         Scene *scene = CTX_data_scene(C);
455         ID *pinid = sbuts->pinid;
456
457         set_texture_context(C, sbuts);
458
459         if (!((sbuts->texture_context == SB_TEXC_OTHER) || BKE_scene_use_new_shading_nodes(scene))) {
460                 if (ct) {
461                         BLI_freelistN(&ct->users);
462                         MEM_freeN(ct);
463                         sbuts->texuser = NULL;
464                 }
465
466                 return;
467         }
468
469         if (!ct) {
470                 ct = MEM_callocN(sizeof(ButsContextTexture), "ButsContextTexture");
471                 sbuts->texuser = ct;
472         }
473         else {
474                 BLI_freelistN(&ct->users);
475         }
476
477         buttons_texture_users_from_context(&ct->users, C, sbuts);
478
479         if (pinid && GS(pinid->name) == ID_TE) {
480                 ct->user = NULL;
481                 ct->texture = (Tex *)pinid;
482         }
483         else {
484                 /* set one user as active based on active index */
485                 if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1))
486                         ct->index = 0;
487
488                 ct->user = BLI_findlink(&ct->users, ct->index);
489                 ct->texture = NULL;
490
491                 if (ct->user) {
492                         if (ct->user->ptr.data) {
493                                 PointerRNA texptr;
494                                 Tex *tex;
495
496                                 /* get texture datablock pointer if it's a property */
497                                 texptr = RNA_property_pointer_get(&ct->user->ptr, ct->user->prop);
498                                 tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? texptr.data : NULL;
499
500                                 ct->texture = tex;
501                         }
502                         else if (ct->user->node && !(ct->user->node->flag & NODE_ACTIVE_TEXTURE)) {
503                                 ButsTextureUser *user;
504
505                                 /* detect change of active texture node in same node tree, in that
506                                  * case we also automatically switch to the other node */
507                                 for (user = ct->users.first; user; user = user->next) {
508                                         if (user->ntree == ct->user->ntree && user->node != ct->user->node) {
509                                                 if (user->node->flag & NODE_ACTIVE_TEXTURE) {
510                                                         ct->user = user;
511                                                         ct->index = BLI_findindex(&ct->users, user);
512                                                         break;
513                                                 }
514                                         }
515                                 }
516                         }
517                 }
518         }
519 }
520
521 static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg))
522 {
523         /* callback when selecting a texture user in the menu */
524         SpaceButs *sbuts = CTX_wm_space_buts(C);
525         ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL;
526         ButsTextureUser *user = (ButsTextureUser *)user_p;
527         PointerRNA texptr;
528         Tex *tex;
529
530         if (!ct)
531                 return;
532
533         /* set user as active */
534         if (user->node) {
535                 ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
536                 ct->texture = NULL;
537         }
538         else {
539                 texptr = RNA_property_pointer_get(&user->ptr, user->prop);
540                 tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? texptr.data : NULL;
541
542                 ct->texture = tex;
543
544                 if (user->ptr.type == &RNA_ParticleSettingsTextureSlot) {
545                         /* stupid exception for particle systems which still uses influence
546                          * from the old texture system, set the active texture slots as well */
547                         ParticleSettings *part = user->ptr.id.data;
548                         int a;
549
550                         for (a = 0; a < MAX_MTEX; a++)
551                                 if (user->ptr.data == part->mtex[a])
552                                         part->texact = a;
553                 }
554
555                 if (sbuts && tex)
556                         sbuts->preview = 1;
557         }
558
559         ct->user = user;
560         ct->index = user->index;
561 }
562
563 static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUSED(arg))
564 {
565         /* callback when opening texture user selection menu, to create buttons. */
566         SpaceButs *sbuts = CTX_wm_space_buts(C);
567         ButsContextTexture *ct = sbuts->texuser;
568         ButsTextureUser *user;
569         uiBlock *block = uiLayoutGetBlock(layout);
570         const char *last_category = NULL;
571
572         for (user = ct->users.first; user; user = user->next) {
573                 uiBut *but;
574                 char name[UI_MAX_NAME_STR];
575
576                 /* add label per category */
577                 if (!last_category || !STREQ(last_category, user->category)) {
578                         uiItemL(layout, IFACE_(user->category), ICON_NONE);
579                         but = block->buttons.last;
580                         but->drawflag = UI_BUT_TEXT_LEFT;
581                 }
582
583                 /* create button */
584                 if (user->prop) {
585                         PointerRNA texptr = RNA_property_pointer_get(&user->ptr, user->prop);
586                         Tex *tex = texptr.data;
587
588                         if (tex)
589                                 BLI_snprintf(name, UI_MAX_NAME_STR, "  %s - %s", user->name, tex->id.name + 2);
590                         else
591                                 BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", user->name);
592                 }
593                 else
594                         BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", user->name);
595
596                 but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, user->icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
597                                        NULL, 0.0, 0.0, 0.0, 0.0, "");
598                 UI_but_funcN_set(but, template_texture_select, MEM_dupallocN(user), NULL);
599
600                 last_category = user->category;
601         }
602
603         UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
604 }
605
606 void uiTemplateTextureUser(uiLayout *layout, bContext *C)
607 {
608         /* texture user selection dropdown menu. the available users have been
609          * gathered before drawing in ButsContextTexture, we merely need to
610          * display the current item. */
611         SpaceButs *sbuts = CTX_wm_space_buts(C);
612         ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL;
613         uiBlock *block = uiLayoutGetBlock(layout);
614         uiBut *but;
615         ButsTextureUser *user;
616         char name[UI_MAX_NAME_STR];
617
618         if (!ct)
619                 return;
620
621         /* get current user */
622         user = ct->user;
623
624         if (!user) {
625                 uiItemL(layout, IFACE_("No textures in context"), ICON_NONE);
626                 return;
627         }
628
629         /* create button */
630         BLI_strncpy(name, user->name, UI_MAX_NAME_STR);
631
632         if (user->icon) {
633                 but = uiDefIconTextMenuBut(block, template_texture_user_menu, NULL,
634                                            user->icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
635         }
636         else {
637                 but = uiDefMenuBut(block, template_texture_user_menu, NULL,
638                                    name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
639         }
640
641         /* some cosmetic tweaks */
642         UI_but_type_set_menu_from_pulldown(but);
643
644         but->flag &= ~UI_BUT_ICON_SUBMENU;
645 }
646
647 /************************* Texture Show **************************/
648
649 static void template_texture_show(bContext *C, void *data_p, void *prop_p)
650 {
651         SpaceButs *sbuts = CTX_wm_space_buts(C);
652         ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL;
653         ButsTextureUser *user;
654
655         if (!ct)
656                 return;
657
658         for (user = ct->users.first; user; user = user->next)
659                 if (user->ptr.data == data_p && user->prop == prop_p)
660                         break;
661         
662         if (user) {
663                 /* select texture */
664                 template_texture_select(C, user, NULL);
665
666                 /* change context */
667                 sbuts->mainb = BCONTEXT_TEXTURE;
668                 sbuts->mainbuser = sbuts->mainb;
669                 sbuts->preview = 1;
670
671                 /* redraw editor */
672                 ED_area_tag_redraw(CTX_wm_area(C));
673         }
674 }
675
676 void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
677 {
678         /* button to quickly show texture in texture tab */
679         SpaceButs *sbuts = CTX_wm_space_buts(C);
680         ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL;
681         ButsTextureUser *user;
682
683         /* only show button in other tabs in properties editor */
684         if (!ct || sbuts->mainb == BCONTEXT_TEXTURE)
685                 return;
686
687         /* find corresponding texture user */
688         for (user = ct->users.first; user; user = user->next)
689                 if (user->ptr.data == ptr->data && user->prop == prop)
690                         break;
691         
692         /* draw button */
693         if (user) {
694                 uiBlock *block = uiLayoutGetBlock(layout);
695                 uiBut *but;
696                 
697                 but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
698                                    NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Show texture in texture tab"));
699                 UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop);
700         }
701 }
702