Blender V2.61 - r43446

buttons_context.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_utildefines.h"
00038 
00039 #include "DNA_armature_types.h"
00040 #include "DNA_lamp_types.h"
00041 #include "DNA_material_types.h"
00042 #include "DNA_node_types.h"
00043 #include "DNA_scene_types.h"
00044 #include "DNA_world_types.h"
00045 #include "DNA_speaker_types.h"
00046 #include "DNA_brush_types.h"
00047 
00048 #include "BKE_context.h"
00049 #include "BKE_action.h"
00050 #include "BKE_material.h"
00051 #include "BKE_modifier.h"
00052 #include "BKE_paint.h"
00053 #include "BKE_particle.h"
00054 #include "BKE_screen.h"
00055 #include "BKE_texture.h"
00056 
00057 #include "RNA_access.h"
00058 
00059 #include "ED_armature.h"
00060 #include "ED_screen.h"
00061 #include "ED_physics.h"
00062 
00063 #include "UI_interface.h"
00064 #include "UI_resources.h"
00065 
00066 #include "buttons_intern.h" // own include
00067 
00068 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
00069 {
00070     PointerRNA *ptr;
00071     int a;
00072 
00073     for(a=0; a<path->len; a++) {
00074         ptr= &path->ptr[a];
00075 
00076         if(RNA_struct_is_a(ptr->type, type)) {
00077             CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
00078             return 1;
00079         }
00080     }
00081 
00082     return 0;
00083 }
00084 
00085 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
00086 {
00087     PointerRNA *ptr;
00088     int a;
00089 
00090     for(a=0; a<path->len; a++) {
00091         ptr= &path->ptr[a];
00092 
00093         if(RNA_struct_is_a(ptr->type, type))
00094             return ptr;
00095     }
00096 
00097     return NULL;
00098 }
00099 
00100 /************************* Creating the Path ************************/
00101 
00102 static int buttons_context_path_scene(ButsContextPath *path)
00103 {
00104     PointerRNA *ptr= &path->ptr[path->len-1];
00105 
00106     /* this one just verifies */
00107     return RNA_struct_is_a(ptr->type, &RNA_Scene);
00108 }
00109 
00110 /* note: this function can return 1 without adding a world to the path
00111  * so the buttons stay visible, but be sure to check the ID type if a ID_WO */
00112 static int buttons_context_path_world(ButsContextPath *path)
00113 {
00114     Scene *scene;
00115     World *world;
00116     PointerRNA *ptr= &path->ptr[path->len-1];
00117 
00118     /* if we already have a (pinned) world, we're done */
00119     if(RNA_struct_is_a(ptr->type, &RNA_World)) {
00120         return 1;
00121     }
00122     /* if we have a scene, use the scene's world */
00123     else if(buttons_context_path_scene(path)) {
00124         scene= path->ptr[path->len-1].data;
00125         world= scene->world;
00126         
00127         if(world) {
00128             RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
00129             path->len++;
00130             return 1;
00131         }
00132         else {
00133             return 1;
00134         }
00135     }
00136 
00137     /* no path to a world possible */
00138     return 0;
00139 }
00140 
00141 
00142 static int buttons_context_path_object(ButsContextPath *path)
00143 {
00144     Scene *scene;
00145     Object *ob;
00146     PointerRNA *ptr= &path->ptr[path->len-1];
00147 
00148     /* if we already have a (pinned) object, we're done */
00149     if(RNA_struct_is_a(ptr->type, &RNA_Object)) {
00150         return 1;
00151     }
00152     /* if we have a scene, use the scene's active object */
00153     else if(buttons_context_path_scene(path)) {
00154         scene= path->ptr[path->len-1].data;
00155         ob= (scene->basact)? scene->basact->object: NULL;
00156 
00157         if(ob) {
00158             RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
00159             path->len++;
00160 
00161             return 1;
00162         }
00163     }
00164 
00165     /* no path to a object possible */
00166     return 0;
00167 }
00168 
00169 static int buttons_context_path_data(ButsContextPath *path, int type)
00170 {
00171     Object *ob;
00172     PointerRNA *ptr= &path->ptr[path->len-1];
00173 
00174     /* if we already have a data, we're done */
00175     if(RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
00176     else if(RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
00177     else if(RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
00178     else if(RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
00179     else if(RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
00180     else if(RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
00181     else if(RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
00182     else if(RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1;
00183     /* try to get an object in the path, no pinning supported here */
00184     else if(buttons_context_path_object(path)) {
00185         ob= path->ptr[path->len-1].data;
00186 
00187         if(ob && (type == -1 || type == ob->type)) {
00188             RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
00189             path->len++;
00190 
00191             return 1;
00192         }
00193     }
00194 
00195     /* no path to data possible */
00196     return 0;
00197 }
00198 
00199 static int buttons_context_path_modifier(ButsContextPath *path)
00200 {
00201     Object *ob;
00202 
00203     if(buttons_context_path_object(path)) {
00204         ob= path->ptr[path->len-1].data;
00205 
00206         if(ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
00207             return 1;
00208     }
00209 
00210     return 0;
00211 }
00212 
00213 static int buttons_context_path_material(ButsContextPath *path, int for_texture)
00214 {
00215     Object *ob;
00216     PointerRNA *ptr= &path->ptr[path->len-1];
00217     Material *ma;
00218 
00219     /* if we already have a (pinned) material, we're done */
00220     if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
00221         return 1;
00222     }
00223     /* if we have an object, use the object material slot */
00224     else if(buttons_context_path_object(path)) {
00225         ob= path->ptr[path->len-1].data;
00226 
00227         if(ob && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
00228             ma= give_current_material(ob, ob->actcol);
00229             RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
00230             path->len++;
00231 
00232             if(for_texture && give_current_material_texture_node(ma))
00233                 return 1;
00234             
00235             ma= give_node_material(ma);
00236             if(ma) {
00237                 RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
00238                 path->len++;
00239             }           
00240             return 1;
00241         }
00242     }
00243 
00244     /* no path to a material possible */
00245     return 0;
00246 }
00247 
00248 static int buttons_context_path_bone(ButsContextPath *path)
00249 {
00250     bArmature *arm;
00251     EditBone *edbo;
00252 
00253     /* if we have an armature, get the active bone */
00254     if(buttons_context_path_data(path, OB_ARMATURE)) {
00255         arm= path->ptr[path->len-1].data;
00256 
00257         if(arm->edbo) {
00258             if(arm->act_edbone) {
00259                 edbo= arm->act_edbone;
00260                 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
00261                 path->len++;
00262                 return 1;
00263             }
00264         }
00265         else {
00266             if(arm->act_bone) {
00267                 RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
00268                 path->len++;
00269                 return 1;
00270             }
00271         }
00272     }
00273 
00274     /* no path to a bone possible */
00275     return 0;
00276 }
00277 
00278 static int buttons_context_path_pose_bone(ButsContextPath *path)
00279 {
00280     PointerRNA *ptr= &path->ptr[path->len-1];
00281 
00282     /* if we already have a (pinned) PoseBone, we're done */
00283     if(RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
00284         return 1;
00285     }
00286 
00287     /* if we have an armature, get the active bone */
00288     if(buttons_context_path_object(path)) {
00289         Object *ob= path->ptr[path->len-1].data;
00290         bArmature *arm= ob->data; /* path->ptr[path->len-1].data - works too */
00291 
00292         if(ob->type != OB_ARMATURE || arm->edbo) {
00293             return 0;
00294         }
00295         else {
00296             if(arm->act_bone) {
00297                 bPoseChannel *pchan= get_pose_channel(ob->pose, arm->act_bone->name);
00298                 if(pchan) {
00299                     RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
00300                     path->len++;
00301                     return 1;
00302                 }
00303             }
00304         }
00305     }
00306 
00307     /* no path to a bone possible */
00308     return 0;
00309 }
00310 
00311 
00312 static int buttons_context_path_particle(ButsContextPath *path)
00313 {
00314     Object *ob;
00315     ParticleSystem *psys;
00316     PointerRNA *ptr= &path->ptr[path->len-1];
00317 
00318     /* if we already have (pinned) particle settings, we're done */
00319     if(RNA_struct_is_a(ptr->type, &RNA_ParticleSettings)) {
00320         return 1;
00321     }
00322     /* if we have an object, get the active particle system */
00323     if(buttons_context_path_object(path)) {
00324         ob= path->ptr[path->len-1].data;
00325 
00326         if(ob && ob->type == OB_MESH) {
00327             psys= psys_get_current(ob);
00328 
00329             RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
00330             path->len++;
00331             return 1;
00332         }
00333     }
00334 
00335     /* no path to a particle system possible */
00336     return 0;
00337 }
00338 
00339 static int buttons_context_path_brush(ButsContextPath *path)
00340 {
00341     Scene *scene;
00342     Brush *br= NULL;
00343     PointerRNA *ptr= &path->ptr[path->len-1];
00344 
00345     /* if we already have a (pinned) brush, we're done */
00346     if(RNA_struct_is_a(ptr->type, &RNA_Brush)) {
00347         return 1;
00348     }
00349     /* if we have a scene, use the toolsettings brushes */
00350     else if(buttons_context_path_scene(path)) {
00351         scene= path->ptr[path->len-1].data;
00352 
00353         if(scene)
00354             br= paint_brush(paint_get_active(scene));
00355 
00356         if(br) {
00357             RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
00358             path->len++;
00359 
00360             return 1;
00361         }
00362     }
00363 
00364     /* no path to a brush possible */
00365     return 0;
00366 }
00367 
00368 static int buttons_context_path_texture(ButsContextPath *path, ButsContextTexture *ct)
00369 {
00370     if(ct) {
00371         /* new shading system */
00372         PointerRNA *ptr= &path->ptr[path->len-1];
00373         ID *id;
00374 
00375         /* if we already have a (pinned) texture, we're done */
00376         if(RNA_struct_is_a(ptr->type, &RNA_Texture))
00377             return 1;
00378 
00379         if(!ct->user)
00380             return 0;
00381         
00382         id= ct->user->id;
00383 
00384         if(id) {
00385             if(GS(id->name) == ID_BR)
00386                 buttons_context_path_brush(path);
00387             else if(GS(id->name) == ID_MA)
00388                 buttons_context_path_material(path, 0);
00389             else if(GS(id->name) == ID_WO)
00390                 buttons_context_path_world(path);
00391             else if(GS(id->name) == ID_LA)
00392                 buttons_context_path_data(path, OB_LAMP);
00393             else if(GS(id->name) == ID_PA)
00394                 buttons_context_path_particle(path);
00395             else if(GS(id->name) == ID_OB)
00396                 buttons_context_path_object(path);
00397         }
00398         
00399         if(ct->texture) {
00400             RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
00401             path->len++;
00402         }
00403 
00404         return 1;
00405     }
00406     else {
00407         /* old shading system */
00408         Material *ma;
00409         Lamp *la;
00410         Brush *br;
00411         World *wo;
00412         ParticleSystem *psys;
00413         Tex *tex;
00414         PointerRNA *ptr= &path->ptr[path->len-1];
00415         int orig_len = path->len;
00416 
00417         /* if we already have a (pinned) texture, we're done */
00418         if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
00419             return 1;
00420         }
00421         /* try brush */
00422         if((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
00423             br= path->ptr[path->len-1].data;
00424             
00425             if(br) {
00426                 tex= give_current_brush_texture(br);
00427 
00428                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00429                 path->len++;
00430                 return 1;
00431             }
00432         }
00433         /* try world */
00434         if((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
00435             wo= path->ptr[path->len-1].data;
00436 
00437             if(wo && GS(wo->id.name)==ID_WO) {
00438                 tex= give_current_world_texture(wo);
00439 
00440                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00441                 path->len++;
00442                 return 1;
00443             }
00444         }
00445         /* try particles */
00446         if((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
00447             if(path->ptr[path->len-1].type == &RNA_ParticleSettings) {
00448                 ParticleSettings *part = path->ptr[path->len-1].data;
00449 
00450                 tex= give_current_particle_texture(part);
00451                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00452                 path->len++;
00453                 return 1;
00454             }
00455             else {
00456                 psys= path->ptr[path->len-1].data;
00457 
00458                 if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
00459                     tex= give_current_particle_texture(psys->part);
00460 
00461                     RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00462                     path->len++;
00463                     return 1;
00464                 }
00465             }
00466         }
00467         /* try material */
00468         if(buttons_context_path_material(path, 1)) {
00469             ma= path->ptr[path->len-1].data;
00470 
00471             if(ma) {
00472                 tex= give_current_material_texture(ma);
00473 
00474                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00475                 path->len++;
00476                 return 1;
00477             }
00478         }
00479         /* try lamp */
00480         if(buttons_context_path_data(path, OB_LAMP)) {
00481             la= path->ptr[path->len-1].data;
00482 
00483             if(la) {
00484                 tex= give_current_lamp_texture(la);
00485 
00486                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00487                 path->len++;
00488                 return 1;
00489             }
00490         }
00491         /* try brushes again in case of no material, lamp, etc */
00492         path->len = orig_len;
00493         if(buttons_context_path_brush(path)) {
00494             br= path->ptr[path->len-1].data;
00495             
00496             if(br) {
00497                 tex= give_current_brush_texture(br);
00498                 
00499                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
00500                 path->len++;
00501                 return 1;
00502             }
00503         }
00504     }
00505 
00506     /* no path to a texture possible */
00507     return 0;
00508 }
00509 
00510 
00511 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
00512 {
00513     SpaceButs *sbuts= CTX_wm_space_buts(C);
00514     ID *id;
00515     int found;
00516 
00517     memset(path, 0, sizeof(*path));
00518     path->flag= flag;
00519     path->tex_ctx = sbuts->texture_context;
00520 
00521     /* if some ID datablock is pinned, set the root pointer */
00522     if(sbuts->pinid) {
00523         id= sbuts->pinid;
00524 
00525         RNA_id_pointer_create(id, &path->ptr[0]);
00526         path->len++;
00527     }
00528 
00529     /* no pinned root, use scene as root */
00530     if(path->len == 0) {
00531         id= (ID*)CTX_data_scene(C);
00532         RNA_id_pointer_create(id, &path->ptr[0]);
00533         path->len++;
00534     }
00535 
00536     /* now for each buttons context type, we try to construct a path,
00537      * tracing back recursively */
00538     switch(mainb) {
00539         case BCONTEXT_SCENE:
00540         case BCONTEXT_RENDER:
00541             found= buttons_context_path_scene(path);
00542             break;
00543         case BCONTEXT_WORLD:
00544             found= buttons_context_path_world(path);
00545             break;
00546         case BCONTEXT_OBJECT:
00547         case BCONTEXT_PHYSICS:
00548         case BCONTEXT_CONSTRAINT:
00549             found= buttons_context_path_object(path);
00550             break;
00551         case BCONTEXT_MODIFIER:
00552             found= buttons_context_path_modifier(path);
00553             break;
00554         case BCONTEXT_DATA:
00555             found= buttons_context_path_data(path, -1);
00556             break;
00557         case BCONTEXT_PARTICLE:
00558             found= buttons_context_path_particle(path);
00559             break;
00560         case BCONTEXT_MATERIAL:
00561             found= buttons_context_path_material(path, 0);
00562             break;
00563         case BCONTEXT_TEXTURE:
00564             found= buttons_context_path_texture(path, sbuts->texuser);
00565             break;
00566         case BCONTEXT_BONE:
00567             found= buttons_context_path_bone(path);
00568             if(!found)
00569                 found= buttons_context_path_data(path, OB_ARMATURE);
00570             break;
00571         case BCONTEXT_BONE_CONSTRAINT:
00572             found= buttons_context_path_pose_bone(path);
00573             break;
00574         default:
00575             found= 0;
00576             break;
00577     }
00578 
00579     return found;
00580 }
00581 
00582 static int buttons_shading_context(const bContext *C, int mainb)
00583 {
00584     Object *ob= CTX_data_active_object(C);
00585 
00586     if(ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
00587         return 1;
00588     if(mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
00589         return 1;
00590     
00591     return 0;
00592 }
00593 
00594 static int buttons_shading_new_context(const bContext *C, int flag)
00595 {
00596     Object *ob= CTX_data_active_object(C);
00597 
00598     if(flag & (1 << BCONTEXT_MATERIAL))
00599         return BCONTEXT_MATERIAL;
00600     else if(ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA)))
00601         return BCONTEXT_DATA;
00602     else if(flag & (1 << BCONTEXT_WORLD))
00603         return BCONTEXT_WORLD;
00604     
00605     return BCONTEXT_RENDER;
00606 }
00607 
00608 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
00609 {
00610     ButsContextPath *path;
00611     PointerRNA *ptr;
00612     int a, pflag= 0, flag= 0;
00613 
00614     buttons_texture_context_compute(C, sbuts);
00615 
00616     if(!sbuts->path)
00617         sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
00618     
00619     path= sbuts->path;
00620     
00621     /* for each context, see if we can compute a valid path to it, if
00622      * this is the case, we know we have to display the button */
00623     for(a=0; a<BCONTEXT_TOT; a++) {
00624         if(buttons_context_path(C, path, a, pflag)) {
00625             flag |= (1<<a);
00626 
00627             /* setting icon for data context */
00628             if(a == BCONTEXT_DATA) {
00629                 ptr= &path->ptr[path->len-1];
00630 
00631                 if(ptr->type)
00632                     sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
00633                 else
00634                     sbuts->dataicon= ICON_EMPTY_DATA;
00635             }
00636         }
00637     }
00638 
00639     /* always try to use the tab that was explicitly
00640      * set to the user, so that once that context comes
00641      * back, the tab is activated again */
00642     sbuts->mainb= sbuts->mainbuser;
00643 
00644     /* in case something becomes invalid, change */
00645     if((flag & (1 << sbuts->mainb)) == 0) {
00646         if(sbuts->flag & SB_SHADING_CONTEXT) {
00647             /* try to keep showing shading related buttons */
00648             sbuts->mainb= buttons_shading_new_context(C, flag);
00649         }
00650         else if(flag & BCONTEXT_OBJECT) {
00651             sbuts->mainb= BCONTEXT_OBJECT;
00652         }
00653         else {
00654             for(a=0; a<BCONTEXT_TOT; a++) {
00655                 if(flag & (1 << a)) {
00656                     sbuts->mainb= a;
00657                     break;
00658                 }
00659             }
00660         }
00661     }
00662 
00663     buttons_context_path(C, path, sbuts->mainb, pflag);
00664 
00665     if(!(flag & (1 << sbuts->mainb))) {
00666         if(flag & (1 << BCONTEXT_OBJECT))
00667             sbuts->mainb= BCONTEXT_OBJECT;
00668         else
00669             sbuts->mainb= BCONTEXT_SCENE;
00670     }
00671 
00672     if(buttons_shading_context(C, sbuts->mainb))
00673         sbuts->flag |= SB_SHADING_CONTEXT;
00674     else
00675         sbuts->flag &= ~SB_SHADING_CONTEXT;
00676 
00677     sbuts->pathflag= flag;
00678 }
00679 
00680 /************************* Context Callback ************************/
00681 
00682 const char *buttons_context_dir[] = {
00683     "world", "object", "mesh", "armature", "lattice", "curve",
00684     "meta_ball", "lamp", "speaker", "camera", "material", "material_slot",
00685     "texture", "texture_slot", "texture_user", "bone", "edit_bone",
00686     "pose_bone", "particle_system", "particle_system_editable",
00687     "cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint", NULL};
00688 
00689 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
00690 {
00691     SpaceButs *sbuts= CTX_wm_space_buts(C);
00692     ButsContextPath *path= sbuts?sbuts->path:NULL;
00693 
00694     if(!path)
00695         return 0;
00696 
00697     /* here we handle context, getting data from precomputed path */
00698     if(CTX_data_dir(member)) {
00699         CTX_data_dir_set(result, buttons_context_dir);
00700         return 1;
00701     }
00702     else if(CTX_data_equals(member, "world")) {
00703         set_pointer_type(path, result, &RNA_World);
00704         return 1;
00705     }
00706     else if(CTX_data_equals(member, "object")) {
00707         set_pointer_type(path, result, &RNA_Object);
00708         return 1;
00709     }
00710     else if(CTX_data_equals(member, "mesh")) {
00711         set_pointer_type(path, result, &RNA_Mesh);
00712         return 1;
00713     }
00714     else if(CTX_data_equals(member, "armature")) {
00715         set_pointer_type(path, result, &RNA_Armature);
00716         return 1;
00717     }
00718     else if(CTX_data_equals(member, "lattice")) {
00719         set_pointer_type(path, result, &RNA_Lattice);
00720         return 1;
00721     }
00722     else if(CTX_data_equals(member, "curve")) {
00723         set_pointer_type(path, result, &RNA_Curve);
00724         return 1;
00725     }
00726     else if(CTX_data_equals(member, "meta_ball")) {
00727         set_pointer_type(path, result, &RNA_MetaBall);
00728         return 1;
00729     }
00730     else if(CTX_data_equals(member, "lamp")) {
00731         set_pointer_type(path, result, &RNA_Lamp);
00732         return 1;
00733     }
00734     else if(CTX_data_equals(member, "camera")) {
00735         set_pointer_type(path, result, &RNA_Camera);
00736         return 1;
00737     }
00738     else if(CTX_data_equals(member, "speaker")) {
00739         set_pointer_type(path, result, &RNA_Speaker);
00740         return 1;
00741     }
00742     else if(CTX_data_equals(member, "material")) {
00743         set_pointer_type(path, result, &RNA_Material);
00744         return 1;
00745     }
00746     else if(CTX_data_equals(member, "texture")) {
00747         ButsContextTexture *ct= sbuts->texuser;
00748 
00749         if(ct) {
00750             /* new shading system */
00751             CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
00752         }
00753         else {
00754             /* old shading system */
00755             set_pointer_type(path, result, &RNA_Texture);
00756         }
00757 
00758         return 1;
00759     }
00760     else if(CTX_data_equals(member, "material_slot")) {
00761         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00762 
00763         if(ptr) {
00764             Object *ob= ptr->data;
00765 
00766             if(ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) {
00767                 /* a valid actcol isn't ensured [#27526] */
00768                 int matnr= ob->actcol-1;
00769                 if(matnr < 0) matnr= 0;
00770                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]);
00771             }
00772         }
00773 
00774         return 1;
00775     }
00776     else if(CTX_data_equals(member, "texture_user")) {
00777         ButsContextTexture *ct= sbuts->texuser;
00778 
00779         if(!ct)
00780             return 0; /* old shading system */
00781 
00782         if(ct->user && ct->user->ptr.data) {
00783             ButsTextureUser *user= ct->user; 
00784             CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data);
00785         }
00786 
00787         return 1;
00788     }
00789     else if(CTX_data_equals(member, "texture_node")) {
00790         ButsContextTexture *ct= sbuts->texuser;
00791 
00792         if(ct) {
00793             /* new shading system */
00794             if(ct->user && ct->user->node)
00795                 CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node);
00796 
00797             return 1;
00798         }
00799         else {
00800             /* old shading system */
00801             PointerRNA *ptr;
00802 
00803             if((ptr=get_pointer_type(path, &RNA_Material))) {
00804                 Material *ma= ptr->data;
00805 
00806                 if(ma) {
00807                     bNode *node= give_current_material_texture_node(ma);
00808                     CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node);
00809                 }
00810             }
00811 
00812             return 1;
00813         }
00814     }
00815     else if(CTX_data_equals(member, "texture_slot")) {
00816         ButsContextTexture *ct= sbuts->texuser;
00817         PointerRNA *ptr;
00818 
00819         if(ct)
00820             return 0; /* new shading system */
00821 
00822         if((ptr=get_pointer_type(path, &RNA_Material))) {
00823             Material *ma= ptr->data;
00824 
00825             /* if we have a node material, get slot from material in material node */
00826             if(ma && ma->use_nodes && ma->nodetree) {
00827                 /* if there's an active texture node in the node tree,
00828                  * then that texture is in context directly, without a texture slot */
00829                 if (give_current_material_texture_node(ma))
00830                     return 0;
00831                 
00832                 ma= give_node_material(ma);
00833                 if (ma)
00834                     CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
00835                 else
00836                     return 0;
00837             } else if(ma) {
00838                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
00839             }
00840         }
00841         else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
00842             Lamp *la= ptr->data;
00843 
00844             if(la)
00845                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
00846         }
00847         else if((ptr=get_pointer_type(path, &RNA_World))) {
00848             World *wo= ptr->data;
00849 
00850             if(wo)
00851                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
00852         }
00853         else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
00854             Brush *br= ptr->data;
00855 
00856             if(br)
00857                 CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
00858         }
00859         else if((ptr=get_pointer_type(path, &RNA_ParticleSystem))) {
00860             ParticleSettings *part= ((ParticleSystem *)ptr->data)->part;
00861 
00862             if(part)
00863                 CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
00864         }
00865 
00866         return 1;
00867     }
00868     else if(CTX_data_equals(member, "bone")) {
00869         set_pointer_type(path, result, &RNA_Bone);
00870         return 1;
00871     }
00872     else if(CTX_data_equals(member, "edit_bone")) {
00873         set_pointer_type(path, result, &RNA_EditBone);
00874         return 1;
00875     }
00876     else if(CTX_data_equals(member, "pose_bone")) {
00877         set_pointer_type(path, result, &RNA_PoseBone);
00878         return 1;
00879     }
00880     else if(CTX_data_equals(member, "particle_system")) {
00881         set_pointer_type(path, result, &RNA_ParticleSystem);
00882         return 1;
00883     }
00884     else if(CTX_data_equals(member, "particle_system_editable")) {
00885         if(PE_poll((bContext*)C))
00886             set_pointer_type(path, result, &RNA_ParticleSystem);
00887         else
00888             CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
00889         return 1;
00890     }   
00891     else if(CTX_data_equals(member, "cloth")) {
00892         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00893 
00894         if(ptr && ptr->data) {
00895             Object *ob= ptr->data;
00896             ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
00897             CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
00898             return 1;
00899         }
00900     }
00901     else if(CTX_data_equals(member, "soft_body")) {
00902         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00903 
00904         if(ptr && ptr->data) {
00905             Object *ob= ptr->data;
00906             ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
00907             CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
00908             return 1;
00909         }
00910     }
00911     else if(CTX_data_equals(member, "fluid")) {
00912         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00913 
00914         if(ptr && ptr->data) {
00915             Object *ob= ptr->data;
00916             ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
00917             CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
00918             return 1;
00919         }
00920     }
00921     
00922     else if(CTX_data_equals(member, "smoke")) {
00923         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00924 
00925         if(ptr && ptr->data) {
00926             Object *ob= ptr->data;
00927             ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
00928             CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
00929             return 1;
00930         }
00931     }
00932     else if(CTX_data_equals(member, "collision")) {
00933         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00934 
00935         if(ptr && ptr->data) {
00936             Object *ob= ptr->data;
00937             ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
00938             CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
00939             return 1;
00940         }
00941     }
00942     else if(CTX_data_equals(member, "brush")) {
00943         set_pointer_type(path, result, &RNA_Brush);
00944         return 1;
00945     }
00946     else if(CTX_data_equals(member, "dynamic_paint")) {
00947         PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
00948 
00949         if(ptr && ptr->data) {
00950             Object *ob= ptr->data;
00951             ModifierData *md= modifiers_findByType(ob, eModifierType_DynamicPaint);
00952             CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
00953             return 1;
00954         }
00955     }
00956     else {
00957         return 0; /* not found */
00958     }
00959 
00960     return -1; /* found but not available */
00961 }
00962 
00963 /************************* Drawing the Path ************************/
00964 
00965 static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
00966 {
00967     SpaceButs *sbuts= CTX_wm_space_buts(C);
00968 
00969     if(sbuts->flag & SB_PIN_CONTEXT) {
00970         sbuts->pinid= buttons_context_id_path(C);
00971     }
00972     else
00973         sbuts->pinid= NULL;
00974     
00975     ED_area_tag_redraw(CTX_wm_area(C));
00976 }
00977 
00978 void buttons_context_draw(const bContext *C, uiLayout *layout)
00979 {
00980     SpaceButs *sbuts= CTX_wm_space_buts(C);
00981     ButsContextPath *path= sbuts->path;
00982     uiLayout *row;
00983     uiBlock *block;
00984     uiBut *but;
00985     PointerRNA *ptr;
00986     char namebuf[128], *name;
00987     int a, icon;
00988 
00989     if(!path)
00990         return;
00991 
00992     row= uiLayoutRow(layout, 1);
00993     uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
00994 
00995     block= uiLayoutGetBlock(row);
00996     uiBlockSetEmboss(block, UI_EMBOSSN);
00997     but= uiDefIconButBitC(block, ICONTOG, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag, 0, 0, 0, 0, "Follow context or keep fixed datablock displayed");
00998     uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
00999     uiButSetFunc(but, pin_cb, NULL, NULL);
01000 
01001     for(a=0; a<path->len; a++) {
01002         ptr= &path->ptr[a];
01003 
01004         if(a != 0)
01005             uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
01006 
01007         if(ptr->data) {
01008             icon= RNA_struct_ui_icon(ptr->type);
01009             name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
01010 
01011             if(name) {
01012                 if(!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
01013                     uiItemLDrag(row, ptr, "", icon); /* save some space */
01014                 else
01015                     uiItemLDrag(row, ptr, name, icon);
01016                                  
01017                 if(name != namebuf)
01018                     MEM_freeN(name);
01019             }
01020             else
01021                 uiItemL(row, "", icon);
01022         }
01023     }
01024 }
01025 
01026 static void buttons_panel_context(const bContext *C, Panel *pa)
01027 {
01028     buttons_context_draw(C, pa->layout);
01029 }
01030 
01031 void buttons_context_register(ARegionType *art)
01032 {
01033     PanelType *pt;
01034 
01035     pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
01036     strcpy(pt->idname, "BUTTONS_PT_context");
01037     strcpy(pt->label, "Context");
01038     pt->draw= buttons_panel_context;
01039     pt->flag= PNL_NO_HEADER;
01040     BLI_addtail(&art->paneltypes, pt);
01041 }
01042 
01043 ID *buttons_context_id_path(const bContext *C)
01044 {
01045     SpaceButs *sbuts= CTX_wm_space_buts(C);
01046     ButsContextPath *path= sbuts->path;
01047     PointerRNA *ptr;
01048     int a;
01049 
01050     if(path->len) {
01051         for(a=path->len-1; a>=0; a--) {
01052             ptr= &path->ptr[a];
01053 
01054             /* pin particle settings instead of system, since only settings are an idblock*/
01055             if(sbuts->mainb == BCONTEXT_PARTICLE && sbuts->flag & SB_PIN_CONTEXT) {
01056                 if(ptr->type == &RNA_ParticleSystem && ptr->data) {
01057                     ParticleSystem *psys = (ParticleSystem *)ptr->data;
01058                     return &psys->part->id;
01059                 }
01060             }
01061 
01062             if(ptr->id.data) {
01063                 return ptr->id.data;
01064                 break;
01065             }
01066         }
01067     }
01068 
01069     return NULL;
01070 }