4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2009 Blender Foundation.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation
25 * ***** END GPL LICENSE BLOCK *****
31 #include "MEM_guardedalloc.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_brush_types.h"
35 #include "DNA_lamp_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_modifier_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 #include "DNA_space_types.h"
42 #include "DNA_particle_types.h"
43 #include "DNA_texture_types.h"
44 #include "DNA_world_types.h"
46 #include "BLI_listbase.h"
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_material.h"
51 #include "BKE_modifier.h"
52 #include "BKE_particle.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
55 #include "BKE_world.h"
57 #include "RNA_access.h"
59 #include "ED_armature.h"
60 #include "ED_screen.h"
62 #include "UI_interface.h"
63 #include "UI_resources.h"
65 #include "buttons_intern.h" // own include
67 typedef struct ButsContextPath {
73 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
78 for(a=0; a<path->len; a++) {
81 if(RNA_struct_is_a(ptr->type, type)) {
82 CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
90 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
95 for(a=0; a<path->len; a++) {
98 if(RNA_struct_is_a(ptr->type, type))
105 /************************* Creating the Path ************************/
107 static int buttons_context_path_scene(ButsContextPath *path)
109 PointerRNA *ptr= &path->ptr[path->len-1];
111 /* this one just verifies */
112 return RNA_struct_is_a(ptr->type, &RNA_Scene);
115 static int buttons_context_path_world(ButsContextPath *path)
118 PointerRNA *ptr= &path->ptr[path->len-1];
120 /* if we already have a (pinned) world, we're done */
121 if(RNA_struct_is_a(ptr->type, &RNA_World)) {
124 /* if we have a scene, use the scene's world */
125 else if(buttons_context_path_scene(path)) {
126 scene= path->ptr[path->len-1].data;
128 RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
134 /* no path to a world possible */
139 static int buttons_context_path_object(ButsContextPath *path)
143 PointerRNA *ptr= &path->ptr[path->len-1];
145 /* if we already have a (pinned) object, we're done */
146 if(RNA_struct_is_a(ptr->type, &RNA_Object)) {
149 /* if we have a scene, use the scene's active object */
150 else if(buttons_context_path_scene(path)) {
151 scene= path->ptr[path->len-1].data;
152 ob= (scene->basact)? scene->basact->object: NULL;
155 RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
162 /* no path to a object possible */
166 static int buttons_context_path_data(ButsContextPath *path, int type)
169 PointerRNA *ptr= &path->ptr[path->len-1];
171 /* if we already have a data, we're done */
172 if(RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
173 else if(RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
174 else if(RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
175 else if(RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
176 else if(RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
177 else if(RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
178 else if(RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
179 /* try to get an object in the path, no pinning supported here */
180 else if(buttons_context_path_object(path)) {
181 ob= path->ptr[path->len-1].data;
183 if(ob && (type == -1 || type == ob->type)) {
184 RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
191 /* no path to data possible */
195 static int buttons_context_path_modifier(ButsContextPath *path)
199 if(buttons_context_path_object(path)) {
200 ob= path->ptr[path->len-1].data;
202 if(ob && ELEM4(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF))
209 static int buttons_context_path_material(ButsContextPath *path)
212 PointerRNA *ptr= &path->ptr[path->len-1];
215 /* if we already have a (pinned) material, we're done */
216 if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
219 /* if we have an object, use the object material slot */
220 else if(buttons_context_path_object(path)) {
221 ob= path->ptr[path->len-1].data;
223 if(ob && ob->type && (ob->type<OB_LAMP)) {
224 ma= give_current_material(ob, ob->actcol);
225 RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
231 /* no path to a material possible */
235 static Bone *find_active_bone(Bone *bone)
239 for(; bone; bone=bone->next) {
240 if(bone->flag & BONE_ACTIVE)
243 active= find_active_bone(bone->childbase.first);
251 static int buttons_context_path_bone(ButsContextPath *path)
257 /* if we have an armature, get the active bone */
258 if(buttons_context_path_data(path, OB_ARMATURE)) {
259 arm= path->ptr[path->len-1].data;
262 for(edbo=arm->edbo->first; edbo; edbo=edbo->next) {
263 if(edbo->flag & BONE_ACTIVE) {
264 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
271 bone= find_active_bone(arm->bonebase.first);
274 RNA_pointer_create(&arm->id, &RNA_Bone, bone, &path->ptr[path->len]);
281 /* no path to a bone possible */
285 static int buttons_context_path_particle(ButsContextPath *path)
288 ParticleSystem *psys;
290 /* if we have an object, get the active particle system */
291 if(buttons_context_path_object(path)) {
292 ob= path->ptr[path->len-1].data;
294 if(ob && ob->type == OB_MESH) {
295 psys= psys_get_current(ob);
297 RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
303 /* no path to a particle system possible */
307 static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
312 PointerRNA *ptr= &path->ptr[path->len-1];
313 const Object *obact = CTX_data_active_object(C);
315 /* if we already have a (pinned) brush, we're done */
316 if(RNA_struct_is_a(ptr->type, &RNA_Brush)) {
319 /* if we have a scene, use the toolsettings brushes */
320 else if(buttons_context_path_scene(path)) {
321 scene= path->ptr[path->len-1].data;
322 ts= scene->toolsettings;
324 if(obact && obact->mode & OB_MODE_SCULPT)
325 br= ts->sculpt->brush;
326 else if(G.f & G_VERTEXPAINT)
327 br= ts->vpaint->brush;
328 else if(G.f & G_WEIGHTPAINT)
329 br= ts->wpaint->brush;
330 else if(G.f & G_TEXTUREPAINT)
331 br= ts->imapaint.brush;
334 RNA_id_pointer_create(&br->id, &path->ptr[path->len]);
341 /* no path to a world possible */
345 static int buttons_context_path_texture(const bContext *C, ButsContextPath *path)
353 PointerRNA *ptr= &path->ptr[path->len-1];
355 /* if we already have a (pinned) texture, we're done */
356 if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
360 else if((path->flag & SB_BRUSH_TEX) && buttons_context_path_brush(C, path)) {
361 br= path->ptr[path->len-1].data;
364 mtex= br->mtex[(int)br->texact];
365 tex= (mtex)? mtex->tex: NULL;
367 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
373 else if((path->flag & SB_WORLD_TEX) && buttons_context_path_world(path)) {
374 wo= path->ptr[path->len-1].data;
377 mtex= wo->mtex[(int)wo->texact];
378 tex= (mtex)? mtex->tex: NULL;
380 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
386 else if(buttons_context_path_material(path)) {
387 ma= path->ptr[path->len-1].data;
390 mtex= ma->mtex[(int)ma->texact];
391 tex= (mtex)? mtex->tex: NULL;
393 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
399 else if(buttons_context_path_data(path, OB_LAMP)) {
400 la= path->ptr[path->len-1].data;
403 mtex= la->mtex[(int)la->texact];
404 tex= (mtex)? mtex->tex: NULL;
406 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
411 /* TODO: material nodes */
413 /* no path to a texture possible */
418 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
420 SpaceButs *sbuts= CTX_wm_space_buts(C);
424 memset(path, 0, sizeof(*path));
427 /* if some ID datablock is pinned, set the root pointer */
431 RNA_id_pointer_create(id, &path->ptr[0]);
435 /* no pinned root, use scene as root */
437 id= (ID*)CTX_data_scene(C);
438 RNA_id_pointer_create(id, &path->ptr[0]);
442 /* now for each buttons context type, we try to construct a path,
443 * tracing back recursively */
446 found= buttons_context_path_scene(path);
449 found= buttons_context_path_world(path);
451 case BCONTEXT_OBJECT:
452 case BCONTEXT_PHYSICS:
453 case BCONTEXT_CONSTRAINT:
454 found= buttons_context_path_object(path);
456 case BCONTEXT_MODIFIER:
457 found= buttons_context_path_modifier(path);
460 found= buttons_context_path_data(path, -1);
462 case BCONTEXT_PARTICLE:
463 found= buttons_context_path_particle(path);
465 case BCONTEXT_MATERIAL:
466 found= buttons_context_path_material(path);
468 case BCONTEXT_TEXTURE:
469 found= buttons_context_path_texture(C, path);
472 found= buttons_context_path_bone(path);
474 found= buttons_context_path_data(path, OB_ARMATURE);
484 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
486 ButsContextPath *path;
488 int a, pflag, flag= 0;
491 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
494 pflag= (sbuts->flag & (SB_WORLD_TEX|SB_BRUSH_TEX));
496 /* for each context, see if we can compute a valid path to it, if
497 * this is the case, we know we have to display the button */
498 for(a=0; a<BCONTEXT_TOT; a++) {
499 if(buttons_context_path(C, path, a, pflag)) {
502 /* setting icon for data context */
503 if(a == BCONTEXT_DATA) {
504 ptr= &path->ptr[path->len-1];
507 sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
509 sbuts->dataicon= ICON_EMPTY_DATA;
514 /* always try to use the tab that was explicitly
515 * set to the user, so that once that context comes
516 * back, the tab is activated again */
517 sbuts->mainb= sbuts->mainbuser;
519 /* in case something becomes invalid, change */
520 if((flag & (1 << sbuts->mainb)) == 0) {
521 if(flag & BCONTEXT_OBJECT) {
522 sbuts->mainb= BCONTEXT_OBJECT;
525 for(a=0; a<BCONTEXT_TOT; a++) {
526 if(flag & (1 << a)) {
534 buttons_context_path(C, path, sbuts->mainb, pflag);
536 if(!(flag & (1 << sbuts->mainb))) {
537 if(flag & (1 << BCONTEXT_OBJECT))
538 sbuts->mainb= BCONTEXT_OBJECT;
540 sbuts->mainb= BCONTEXT_SCENE;
543 sbuts->pathflag= flag;
546 /************************* Context Callback ************************/
548 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
550 SpaceButs *sbuts= CTX_wm_space_buts(C);
551 ButsContextPath *path= sbuts?sbuts->path:NULL;
556 /* here we handle context, getting data from precomputed path */
557 if(CTX_data_dir(member)) {
558 static const char *dir[] = {
559 "world", "object", "mesh", "armature", "lattice", "curve",
560 "meta_ball", "lamp", "camera", "material", "material_slot",
561 "texture", "texture_slot", "bone", "edit_bone", "particle_system",
562 "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
564 CTX_data_dir_set(result, dir);
567 else if(CTX_data_equals(member, "world")) {
568 set_pointer_type(path, result, &RNA_World);
571 else if(CTX_data_equals(member, "object")) {
572 set_pointer_type(path, result, &RNA_Object);
575 else if(CTX_data_equals(member, "mesh")) {
576 set_pointer_type(path, result, &RNA_Mesh);
579 else if(CTX_data_equals(member, "armature")) {
580 set_pointer_type(path, result, &RNA_Armature);
583 else if(CTX_data_equals(member, "lattice")) {
584 set_pointer_type(path, result, &RNA_Lattice);
587 else if(CTX_data_equals(member, "curve")) {
588 set_pointer_type(path, result, &RNA_Curve);
591 else if(CTX_data_equals(member, "meta_ball")) {
592 set_pointer_type(path, result, &RNA_MetaBall);
595 else if(CTX_data_equals(member, "lamp")) {
596 set_pointer_type(path, result, &RNA_Lamp);
599 else if(CTX_data_equals(member, "camera")) {
600 set_pointer_type(path, result, &RNA_Camera);
603 else if(CTX_data_equals(member, "material")) {
604 set_pointer_type(path, result, &RNA_Material);
607 else if(CTX_data_equals(member, "texture")) {
608 set_pointer_type(path, result, &RNA_Texture);
611 else if(CTX_data_equals(member, "material_slot")) {
612 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
615 Object *ob= ptr->data;
617 if(ob && ob->type && (ob->type<OB_LAMP) && ob->totcol)
618 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
623 else if(CTX_data_equals(member, "texture_slot")) {
626 if((ptr=get_pointer_type(path, &RNA_Material))) {
627 Material *ma= ptr->data;
630 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
632 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
636 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
638 else if((ptr=get_pointer_type(path, &RNA_World))) {
639 World *wo= ptr->data;
642 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
644 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
645 Brush *br= ptr->data;
648 CTX_data_pointer_set(result, &br->id, &RNA_TextureSlot, br->mtex[(int)br->texact]);
653 else if(CTX_data_equals(member, "bone")) {
654 set_pointer_type(path, result, &RNA_Bone);
657 else if(CTX_data_equals(member, "edit_bone")) {
658 set_pointer_type(path, result, &RNA_EditBone);
661 else if(CTX_data_equals(member, "particle_system")) {
662 set_pointer_type(path, result, &RNA_ParticleSystem);
665 else if(CTX_data_equals(member, "cloth")) {
666 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
668 if(ptr && ptr->data) {
669 Object *ob= ptr->data;
670 ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
671 CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
675 else if(CTX_data_equals(member, "soft_body")) {
676 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
678 if(ptr && ptr->data) {
679 Object *ob= ptr->data;
680 ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
681 CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
685 else if(CTX_data_equals(member, "fluid")) {
686 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
688 if(ptr && ptr->data) {
689 Object *ob= ptr->data;
690 ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
691 CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
696 else if(CTX_data_equals(member, "smoke")) {
697 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
699 if(ptr && ptr->data) {
700 Object *ob= ptr->data;
701 ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
702 CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
706 else if(CTX_data_equals(member, "collision")) {
707 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
709 if(ptr && ptr->data) {
710 Object *ob= ptr->data;
711 ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
712 CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
716 else if(CTX_data_equals(member, "brush")) {
717 set_pointer_type(path, result, &RNA_Brush);
724 /************************* Drawing the Path ************************/
726 static void pin_cb(bContext *C, void *arg1, void *arg2)
728 SpaceButs *sbuts= CTX_wm_space_buts(C);
729 ButsContextPath *path= sbuts->path;
733 if(sbuts->flag & SB_PIN_CONTEXT) {
735 for(a=path->len-1; a>=0; a--) {
739 sbuts->pinid= ptr->id.data;
748 ED_area_tag_redraw(CTX_wm_area(C));
751 void buttons_context_draw(const bContext *C, uiLayout *layout)
753 SpaceButs *sbuts= CTX_wm_space_buts(C);
754 ButsContextPath *path= sbuts->path;
759 char namebuf[128], *name;
765 row= uiLayoutRow(layout, 1);
766 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
768 block= uiLayoutGetBlock(row);
769 uiBlockSetEmboss(block, UI_EMBOSSN);
770 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.");
771 uiButSetFunc(but, pin_cb, NULL, NULL);
773 for(a=0; a<path->len; a++) {
777 uiDefIconBut(block, LABEL, 0, VICON_SMALL_TRI_RIGHT, 0, 0, 10, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
780 icon= RNA_struct_ui_icon(ptr->type);
781 name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf));
784 if(sbuts->mainb != BCONTEXT_SCENE && ptr->type == &RNA_Scene)
785 uiItemL(row, "", icon); /* save some space */
787 uiItemL(row, name, icon);
793 uiItemL(row, "", icon);
798 static void buttons_panel_context(const bContext *C, Panel *pa)
800 buttons_context_draw(C, pa->layout);
803 void buttons_context_register(ARegionType *art)
807 pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
808 strcpy(pt->idname, "BUTTONS_PT_context");
809 strcpy(pt->label, "Context");
810 pt->draw= buttons_panel_context;
811 pt->flag= PNL_NO_HEADER;
812 BLI_addtail(&art->paneltypes, pt);