Blender V2.61 - r43446

buttons_texture.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Blender Foundation
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdlib.h>
00032 #include <string.h>
00033 
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "BLI_listbase.h"
00037 #include "BLI_string.h"
00038 #include "BLI_utildefines.h"
00039 
00040 #include "DNA_brush_types.h"
00041 #include "DNA_ID.h"
00042 #include "DNA_lamp_types.h"
00043 #include "DNA_material_types.h"
00044 #include "DNA_node_types.h"
00045 #include "DNA_object_types.h"
00046 #include "DNA_object_force.h"
00047 #include "DNA_particle_types.h"
00048 #include "DNA_scene_types.h"
00049 #include "DNA_screen_types.h"
00050 #include "DNA_space_types.h"
00051 #include "DNA_world_types.h"
00052 
00053 #include "BKE_context.h"
00054 #include "BKE_material.h"
00055 #include "BKE_modifier.h"
00056 #include "BKE_node.h"
00057 #include "BKE_paint.h"
00058 #include "BKE_particle.h"
00059 #include "BKE_scene.h"
00060 
00061 #include "RNA_access.h"
00062 
00063 #include "UI_interface.h"
00064 #include "UI_resources.h"
00065 
00066 #include "ED_node.h"
00067 #include "ED_screen.h"
00068 
00069 #include "../interface/interface_intern.h"
00070 
00071 #include "buttons_intern.h" // own include
00072 
00073 /************************* Texture User **************************/
00074 
00075 static void buttons_texture_user_property_add(ListBase *users, ID *id, 
00076     PointerRNA ptr, PropertyRNA *prop,
00077     const char *category, int icon, const char *name)
00078 {
00079     ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
00080 
00081     user->id= id;
00082     user->ptr = ptr;
00083     user->prop = prop;
00084     user->category = category;
00085     user->icon = icon;
00086     user->name = name;
00087     user->index = BLI_countlist(users);
00088 
00089     BLI_addtail(users, user);
00090 }
00091 
00092 static void buttons_texture_user_node_add(ListBase *users, ID *id, 
00093     bNodeTree *ntree, bNode *node,
00094     const char *category, int icon, const char *name)
00095 {
00096     ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
00097 
00098     user->id= id;
00099     user->ntree = ntree;
00100     user->node = node;
00101     user->category = category;
00102     user->icon = icon;
00103     user->name = name;
00104     user->index = BLI_countlist(users);
00105 
00106     BLI_addtail(users, user);
00107 }
00108 
00109 static void buttons_texture_users_find_nodetree(ListBase *users, ID *id,
00110     bNodeTree *ntree, const char *category)
00111 {
00112     bNode *node;
00113 
00114     if(ntree) {
00115         for(node=ntree->nodes.first; node; node=node->next) {
00116             if(node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
00117                 PointerRNA ptr;
00118                 /* PropertyRNA *prop; */ /* UNUSED */
00119 
00120                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
00121                 /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */
00122 
00123                 buttons_texture_user_node_add(users, id, ntree, node,
00124                     category, RNA_struct_ui_icon(ptr.type), node->name);
00125             }
00126             else if(node->type == NODE_GROUP && node->id) {
00127                 buttons_texture_users_find_nodetree(users, id, (bNodeTree*)node->id, category);
00128             }
00129         }
00130     }
00131 }
00132 
00133 static void buttons_texture_modifier_foreach(void *userData, Object *ob, ModifierData *md, const char *propname)
00134 {
00135     PointerRNA ptr;
00136     PropertyRNA *prop;
00137     ListBase *users = userData;
00138 
00139     RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
00140     prop = RNA_struct_find_property(&ptr, propname);
00141 
00142     buttons_texture_user_property_add(users, &ob->id, ptr, prop,
00143         "Modifiers", RNA_struct_ui_icon(ptr.type), md->name);
00144 }
00145 
00146 static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
00147 {
00148     Scene *scene= NULL;
00149     Object *ob= NULL;
00150     Material *ma= NULL;
00151     Lamp *la= NULL;
00152     World *wrld= NULL;
00153     Brush *brush= NULL;
00154     ID *pinid = sbuts->pinid;
00155 
00156     /* get data from context */
00157     if(pinid) {
00158         if(GS(pinid->name) == ID_SCE)
00159             scene= (Scene*)pinid;
00160         else if(GS(pinid->name) == ID_OB)
00161             ob= (Object*)pinid;
00162         else if(GS(pinid->name) == ID_LA)
00163             la= (Lamp*)pinid;
00164         else if(GS(pinid->name) == ID_WO)
00165             wrld= (World*)pinid;
00166         else if(GS(pinid->name) == ID_MA)
00167             ma= (Material*)pinid;
00168         else if(GS(pinid->name) == ID_BR)
00169             brush= (Brush*)pinid;
00170     }
00171 
00172     if(!scene)
00173         scene= CTX_data_scene(C);
00174     
00175     if(!(pinid || pinid == &scene->id)) {
00176         ob= (scene->basact)? scene->basact->object: NULL;
00177         wrld= scene->world;
00178         brush= paint_brush(paint_get_active(scene));
00179     }
00180 
00181     if(ob && ob->type == OB_LAMP && !la)
00182         la= ob->data;
00183     if(ob && !ma)
00184         ma= give_current_material(ob, ob->actcol);
00185 
00186     /* fill users */
00187     users->first = users->last = NULL;
00188 
00189     if(ma)
00190         buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, "Material");
00191     if(la)
00192         buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, "Lamp");
00193     if(wrld)
00194         buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, "World");
00195 
00196     if(ob) {
00197         ParticleSystem *psys= psys_get_current(ob);
00198         MTex *mtex;
00199         int a;
00200 
00201         /* modifiers */
00202         modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
00203 
00204         /* particle systems */
00205         if(psys) {
00206             /* todo: these slots are not in the UI */
00207             for(a=0; a<MAX_MTEX; a++) {
00208                 mtex = psys->part->mtex[a];
00209 
00210                 if(mtex) {
00211                     PointerRNA ptr;
00212                     PropertyRNA *prop;
00213 
00214                     RNA_pointer_create(&psys->part->id, &RNA_ParticleSettingsTextureSlot, mtex, &ptr);
00215                     prop = RNA_struct_find_property(&ptr, "texture");
00216 
00217                     buttons_texture_user_property_add(users, &psys->part->id, ptr, prop,
00218                         "Particles", RNA_struct_ui_icon(&RNA_ParticleSettings), psys->name);
00219                 }
00220             }
00221         }
00222 
00223         /* field */
00224         if(ob->pd && ob->pd->forcefield == PFIELD_TEXTURE) {
00225             PointerRNA ptr;
00226             PropertyRNA *prop;
00227 
00228             RNA_pointer_create(&ob->id, &RNA_FieldSettings, ob->pd, &ptr);
00229             prop = RNA_struct_find_property(&ptr, "texture");
00230 
00231             buttons_texture_user_property_add(users, &ob->id, ptr, prop,
00232                 "Fields", ICON_FORCE_TEXTURE, "Texture Field");
00233         }
00234     }
00235 
00236     /* brush */
00237     if(brush) {
00238         PointerRNA ptr;
00239         PropertyRNA *prop;
00240 
00241         RNA_pointer_create(&brush->id, &RNA_BrushTextureSlot, &brush->mtex, &ptr);
00242         prop= RNA_struct_find_property(&ptr, "texture");
00243 
00244         buttons_texture_user_property_add(users, &brush->id, ptr, prop,
00245             "Brush", ICON_BRUSH_DATA, brush->id.name+2);
00246     }
00247 }
00248 
00249 void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
00250 {
00251     /* gatheravailable texture users in context. runs on every draw of
00252        properties editor, before the buttons are created. */
00253     ButsContextTexture *ct= sbuts->texuser;
00254     Scene *scene= CTX_data_scene(C);
00255 
00256     if(!scene_use_new_shading_nodes(scene)) {
00257         if(ct) {
00258             BLI_freelistN(&ct->users);
00259             MEM_freeN(ct);
00260             sbuts->texuser= NULL;
00261         }
00262         
00263         return;
00264     }
00265 
00266     if(!ct) {
00267         ct= MEM_callocN(sizeof(ButsContextTexture), "ButsContextTexture");
00268         sbuts->texuser= ct;
00269     }
00270     else {
00271         BLI_freelistN(&ct->users);
00272     }
00273 
00274     buttons_texture_users_from_context(&ct->users, C, sbuts);
00275 
00276     /* set one user as active based on active index */
00277     if(ct->index >= BLI_countlist(&ct->users))
00278         ct->index= 0;
00279 
00280     ct->user = BLI_findlink(&ct->users, ct->index);
00281     ct->texture = NULL;
00282 
00283     if(ct->user) {
00284         if(ct->user->ptr.data) {
00285             PointerRNA texptr;
00286             Tex *tex;
00287 
00288             /* get texture datablock pointer if it's a property */
00289             texptr = RNA_property_pointer_get(&ct->user->ptr, ct->user->prop);
00290             tex = (RNA_struct_is_a(texptr.type, &RNA_Texture))? texptr.data: NULL;
00291 
00292             ct->texture = tex;
00293         }
00294         else if(ct->user->node && !(ct->user->node->flag & NODE_ACTIVE_TEXTURE)) {
00295             ButsTextureUser *user;
00296 
00297             /* detect change of active texture node in same node tree, in that
00298                case we also automatically switch to the other node */
00299             for(user=ct->users.first; user; user=user->next) {
00300                 if(user->ntree == ct->user->ntree && user->node != ct->user->node) {
00301                     if(user->node->flag & NODE_ACTIVE_TEXTURE) {
00302                         ct->user = user;
00303                         ct->index = BLI_findindex(&ct->users, user);
00304                         break;
00305                     }
00306                 }
00307             }
00308         }
00309     }
00310 }
00311 
00312 static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg))
00313 {
00314     /* callback when selecting a texture user in the menu */
00315     SpaceButs *sbuts = CTX_wm_space_buts(C);
00316     ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
00317     ButsTextureUser *user = (ButsTextureUser*)user_p;
00318     PointerRNA texptr;
00319     Tex *tex;
00320 
00321     if(!ct)
00322         return;
00323 
00324     /* set user as active */
00325     if(user->node) {
00326         ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
00327         ct->texture = NULL;
00328     }
00329     else {
00330         texptr = RNA_property_pointer_get(&user->ptr, user->prop);
00331         tex = (RNA_struct_is_a(texptr.type, &RNA_Texture))? texptr.data: NULL;
00332 
00333         ct->texture = tex;
00334     }
00335 
00336     ct->user = user;
00337     ct->index = user->index;
00338 }
00339 
00340 static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUSED(arg))
00341 {
00342     /* callback when opening texture user selection menu, to create buttons. */
00343     SpaceButs *sbuts = CTX_wm_space_buts(C);
00344     ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
00345     ButsTextureUser *user;
00346     uiBlock *block = uiLayoutGetBlock(layout);
00347     const char *last_category = NULL;
00348 
00349     for(user=ct->users.first; user; user=user->next) {
00350         uiBut *but;
00351         char name[UI_MAX_NAME_STR];
00352 
00353         /* add label per category */
00354         if(!last_category || strcmp(last_category, user->category) != 0) {
00355             uiItemL(layout, user->category, ICON_NONE);
00356             but= block->buttons.last;
00357             but->flag= UI_TEXT_LEFT;
00358         }
00359 
00360         /* create button */
00361         BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", user->name);
00362 
00363         but = uiDefIconTextBut(block, BUT, 0, user->icon, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
00364             NULL, 0.0, 0.0, 0.0, 0.0, "");
00365         uiButSetNFunc(but, template_texture_select, MEM_dupallocN(user), NULL);
00366 
00367         last_category = user->category;
00368     }
00369 }
00370 
00371 void uiTemplateTextureUser(uiLayout *layout, bContext *C)
00372 {
00373     /* texture user selection dropdown menu. the available users have been
00374        gathered before drawing in ButsContextTexture, we merely need to
00375        display the current item. */
00376     SpaceButs *sbuts = CTX_wm_space_buts(C);
00377     ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
00378     uiBlock *block = uiLayoutGetBlock(layout);
00379     uiBut *but;
00380     ButsTextureUser *user;
00381     char name[UI_MAX_NAME_STR];
00382 
00383     if(!ct)
00384         return;
00385 
00386     /* get current user */
00387     user= ct->user;
00388 
00389     if(!user) {
00390         uiItemL(layout, "No textures in context.", ICON_NONE);
00391         return;
00392     }
00393 
00394     /* create button */
00395     BLI_snprintf(name, UI_MAX_NAME_STR, "%s", user->name);
00396 
00397     if(user->icon) {
00398         but= uiDefIconTextMenuBut(block, template_texture_user_menu, NULL,
00399             user->icon, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
00400     }
00401     else {
00402         but= uiDefMenuBut(block, template_texture_user_menu, NULL,
00403             name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
00404     }
00405 
00406     /* some cosmetic tweaks */
00407     but->type= MENU;
00408     but->flag |= UI_TEXT_LEFT;
00409     but->flag &= ~UI_ICON_SUBMENU;
00410 }
00411 
00412 /************************* Texture Show **************************/
00413 
00414 static void template_texture_show(bContext *C, void *data_p, void *prop_p)
00415 {
00416     SpaceButs *sbuts = CTX_wm_space_buts(C);
00417     ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
00418     ButsTextureUser *user;
00419 
00420     if(!ct)
00421         return;
00422 
00423     for(user=ct->users.first; user; user=user->next)
00424         if(user->ptr.data == data_p && user->prop == prop_p)
00425             break;
00426     
00427     if(user) {
00428         /* select texture */
00429         template_texture_select(C, user, NULL);
00430 
00431         /* change context */
00432         sbuts->mainb= BCONTEXT_TEXTURE;
00433         sbuts->mainbuser= sbuts->mainb;
00434         sbuts->preview= 1;
00435 
00436         /* redraw editor */
00437         ED_area_tag_redraw(CTX_wm_area(C));
00438     }
00439 }
00440 
00441 void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
00442 {
00443     /* button to quickly show texture in texture tab */
00444     SpaceButs *sbuts = CTX_wm_space_buts(C);
00445     ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
00446     ButsTextureUser *user;
00447 
00448     /* only show button in other tabs in properties editor */
00449     if(!ct || sbuts->mainb == BCONTEXT_TEXTURE)
00450         return;
00451 
00452     /* find corresponding texture user */
00453     for(user=ct->users.first; user; user=user->next)
00454         if(user->ptr.data == ptr->data && user->prop == prop)
00455             break;
00456     
00457     /* draw button */
00458     if(user) {
00459         uiBlock *block = uiLayoutGetBlock(layout);
00460         uiBut *but;
00461         
00462         but= uiDefIconBut(block, BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
00463             NULL, 0.0, 0.0, 0.0, 0.0, "Show texture in texture tab");
00464         uiButSetFunc(but, template_texture_show, user->ptr.data, user->prop);
00465     }
00466 }
00467