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