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