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