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_lamp_types.h"
35 #include "DNA_material_types.h"
36 #include "DNA_modifier_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_space_types.h"
41 #include "DNA_particle_types.h"
42 #include "DNA_texture_types.h"
43 #include "DNA_world_types.h"
45 #include "BLI_listbase.h"
47 #include "BKE_context.h"
48 #include "BKE_material.h"
49 #include "BKE_modifier.h"
50 #include "BKE_particle.h"
51 #include "BKE_screen.h"
52 #include "BKE_utildefines.h"
53 #include "BKE_world.h"
55 #include "RNA_access.h"
57 #include "ED_screen.h"
59 #include "UI_interface.h"
60 #include "UI_resources.h"
62 #include "buttons_intern.h" // own include
64 typedef struct ButsContextPath {
70 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
75 for(a=0; a<path->len; a++) {
78 if(RNA_struct_is_a(ptr->type, type)) {
79 CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
87 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
92 for(a=0; a<path->len; a++) {
95 if(RNA_struct_is_a(ptr->type, type))
102 /************************* Creating the Path ************************/
104 static int buttons_context_path_scene(ButsContextPath *path)
106 PointerRNA *ptr= &path->ptr[path->len-1];
108 /* this one just verifies */
109 return RNA_struct_is_a(ptr->type, &RNA_Scene);
112 static int buttons_context_path_world(ButsContextPath *path)
115 PointerRNA *ptr= &path->ptr[path->len-1];
117 /* if we already have a (pinned) world, we're done */
118 if(RNA_struct_is_a(ptr->type, &RNA_World)) {
121 /* if we have a scene, use the scene's world */
122 else if(buttons_context_path_scene(path)) {
123 scene= path->ptr[path->len-1].data;
125 RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
131 /* no path to a world possible */
136 static int buttons_context_path_object(ButsContextPath *path)
140 PointerRNA *ptr= &path->ptr[path->len-1];
142 /* if we already have a (pinned) object, we're done */
143 if(RNA_struct_is_a(ptr->type, &RNA_Object)) {
146 /* if we have a scene, use the scene's active object */
147 else if(buttons_context_path_scene(path)) {
148 scene= path->ptr[path->len-1].data;
149 ob= (scene->basact)? scene->basact->object: NULL;
152 RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
159 /* no path to a object possible */
163 static int buttons_context_path_data(ButsContextPath *path, int type)
166 PointerRNA *ptr= &path->ptr[path->len-1];
168 /* if we already have a data, we're done */
169 if(RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
170 else if(RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
171 else if(RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
172 else if(RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
173 else if(RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
174 else if(RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
175 else if(RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
176 /* try to get an object in the path, no pinning supported here */
177 else if(buttons_context_path_object(path)) {
178 ob= path->ptr[path->len-1].data;
180 if(ob && (type == -1 || type == ob->type)) {
181 RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
188 /* no path to data possible */
192 static int buttons_context_path_modifier(ButsContextPath *path)
196 if(buttons_context_path_object(path)) {
197 ob= path->ptr[path->len-1].data;
199 if(ob && ELEM4(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF))
206 static int buttons_context_path_material(ButsContextPath *path)
209 PointerRNA *ptr= &path->ptr[path->len-1];
212 /* if we already have a (pinned) material, we're done */
213 if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
216 /* if we have an object, use the object material slot */
217 else if(buttons_context_path_object(path)) {
218 ob= path->ptr[path->len-1].data;
220 if(ob && ob->type && (ob->type<OB_LAMP)) {
221 ma= give_current_material(ob, ob->actcol);
222 RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
228 /* no path to a material possible */
232 static Bone *find_active_bone(Bone *bone)
236 for(; bone; bone=bone->next) {
237 if(bone->flag & BONE_ACTIVE)
240 active= find_active_bone(bone->childbase.first);
248 static int buttons_context_path_bone(ButsContextPath *path)
253 /* if we have an armature, get the active bone */
254 if(buttons_context_path_data(path, OB_ARMATURE)) {
255 arm= path->ptr[path->len-1].data;
256 bone= find_active_bone(arm->bonebase.first);
259 RNA_pointer_create(&arm->id, &RNA_Bone, bone, &path->ptr[path->len]);
265 /* no path to a bone possible */
269 static int buttons_context_path_particle(ButsContextPath *path)
272 ParticleSystem *psys;
274 /* if we have an object, get the active particle system */
275 if(buttons_context_path_object(path)) {
276 ob= path->ptr[path->len-1].data;
278 if(ob && ob->type == OB_MESH) {
279 psys= psys_get_current(ob);
281 RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
287 /* no path to a particle system possible */
291 static int buttons_context_path_texture(ButsContextPath *path)
298 PointerRNA *ptr= &path->ptr[path->len-1];
300 /* if we already have a (pinned) texture, we're done */
301 if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
305 else if(path->worldtex && buttons_context_path_world(path)) {
306 wo= path->ptr[path->len-1].data;
309 mtex= wo->mtex[(int)wo->texact];
310 tex= (mtex)? mtex->tex: NULL;
312 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
318 else if(buttons_context_path_material(path)) {
319 ma= path->ptr[path->len-1].data;
322 mtex= ma->mtex[(int)ma->texact];
323 tex= (mtex)? mtex->tex: NULL;
325 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
331 else if(buttons_context_path_data(path, OB_LAMP)) {
332 la= path->ptr[path->len-1].data;
335 mtex= la->mtex[(int)la->texact];
336 tex= (mtex)? mtex->tex: NULL;
338 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
343 /* TODO: material nodes, brush */
345 /* no path to a particle system possible */
349 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int worldtex)
351 SpaceButs *sbuts= (SpaceButs*)CTX_wm_space_data(C);
355 memset(path, 0, sizeof(*path));
356 path->worldtex= worldtex;
358 /* if some ID datablock is pinned, set the root pointer */
362 RNA_id_pointer_create(id, &path->ptr[0]);
366 /* no pinned root, use scene as root */
368 id= (ID*)CTX_data_scene(C);
369 RNA_id_pointer_create(id, &path->ptr[0]);
373 /* now for each buttons context type, we try to construct a path,
374 * tracing back recursively */
377 found= buttons_context_path_scene(path);
380 found= buttons_context_path_world(path);
382 case BCONTEXT_OBJECT:
383 case BCONTEXT_PHYSICS:
384 case BCONTEXT_CONSTRAINT:
385 found= buttons_context_path_object(path);
387 case BCONTEXT_MODIFIER:
388 found= buttons_context_path_modifier(path);
391 found= buttons_context_path_data(path, -1);
393 case BCONTEXT_PARTICLE:
394 found= buttons_context_path_particle(path);
396 case BCONTEXT_MATERIAL:
397 found= buttons_context_path_material(path);
399 case BCONTEXT_TEXTURE:
400 found= buttons_context_path_texture(path);
403 found= buttons_context_path_bone(path);
413 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
415 ButsContextPath *path;
417 int a, worldtex, flag= 0;
420 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
423 worldtex= (sbuts->flag & SB_WORLD_TEX);
425 /* for each context, see if we can compute a valid path to it, if
426 * this is the case, we know we have to display the button */
427 for(a=0; a<BCONTEXT_TOT; a++) {
428 if(buttons_context_path(C, path, a, worldtex)) {
431 /* setting icon for data context */
432 if(a == BCONTEXT_DATA) {
433 ptr= &path->ptr[path->len-1];
436 sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
438 sbuts->dataicon= ICON_EMPTY_DATA;
443 /* in case something becomes invalid, change */
444 if((flag & (1 << sbuts->mainb)) == 0) {
445 if(flag & BCONTEXT_OBJECT) {
446 sbuts->mainb= BCONTEXT_OBJECT;
449 for(a=0; a<BCONTEXT_TOT; a++) {
450 if(flag & (1 << a)) {
458 buttons_context_path(C, path, sbuts->mainb, worldtex);
460 if(!(flag & (1 << sbuts->mainb))) {
461 if(flag & (1 << BCONTEXT_OBJECT))
462 sbuts->mainb= BCONTEXT_OBJECT;
464 sbuts->mainb= BCONTEXT_SCENE;
467 sbuts->pathflag= flag;
470 /************************* Context Callback ************************/
472 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
474 SpaceButs *sbuts= (SpaceButs*)CTX_wm_space_data(C);
475 ButsContextPath *path= sbuts?sbuts->path:NULL;
480 /* here we handle context, getting data from precomputed path */
482 if(CTX_data_equals(member, "world")) {
483 set_pointer_type(path, result, &RNA_World);
486 else if(CTX_data_equals(member, "object")) {
487 set_pointer_type(path, result, &RNA_Object);
490 else if(CTX_data_equals(member, "mesh")) {
491 set_pointer_type(path, result, &RNA_Mesh);
494 else if(CTX_data_equals(member, "armature")) {
495 set_pointer_type(path, result, &RNA_Armature);
498 else if(CTX_data_equals(member, "lattice")) {
499 set_pointer_type(path, result, &RNA_Lattice);
502 else if(CTX_data_equals(member, "curve")) {
503 set_pointer_type(path, result, &RNA_Curve);
506 else if(CTX_data_equals(member, "meta_ball")) {
507 set_pointer_type(path, result, &RNA_MetaBall);
510 else if(CTX_data_equals(member, "lamp")) {
511 set_pointer_type(path, result, &RNA_Lamp);
514 else if(CTX_data_equals(member, "camera")) {
515 set_pointer_type(path, result, &RNA_Camera);
518 else if(CTX_data_equals(member, "material")) {
519 set_pointer_type(path, result, &RNA_Material);
522 else if(CTX_data_equals(member, "texture")) {
523 set_pointer_type(path, result, &RNA_Texture);
526 else if(CTX_data_equals(member, "material_slot")) {
527 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
530 Object *ob= ptr->data;
532 if(ob && ob->type && (ob->type<OB_LAMP))
533 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
538 else if(CTX_data_equals(member, "texture_slot")) {
541 if((ptr=get_pointer_type(path, &RNA_Material))) {
542 Material *ma= ptr->data;
545 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
547 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
551 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
553 else if((ptr=get_pointer_type(path, &RNA_World))) {
554 World *wo= ptr->data;
557 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
559 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
560 Brush *br= ptr->data;
563 CTX_data_pointer_set(result, &br->id, &RNA_TextureSlot, br->mtex[(int)br->texact]);
568 else if(CTX_data_equals(member, "bone")) {
569 set_pointer_type(path, result, &RNA_Bone);
572 else if(CTX_data_equals(member, "particle_system")) {
573 set_pointer_type(path, result, &RNA_ParticleSystem);
576 else if(CTX_data_equals(member, "cloth")) {
577 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
579 if(ptr && ptr->data) {
580 Object *ob= ptr->data;
581 ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
582 CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
586 else if(CTX_data_equals(member, "soft_body")) {
587 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
589 if(ptr && ptr->data) {
590 Object *ob= ptr->data;
591 CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodySettings, ob->soft);
595 else if(CTX_data_equals(member, "fluid")) {
596 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
598 if(ptr && ptr->data) {
599 Object *ob= ptr->data;
600 ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
601 CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
609 /************************* Drawing the Path ************************/
611 static void pin_cb(bContext *C, void *arg1, void *arg2)
613 SpaceButs *sbuts= (SpaceButs*)CTX_wm_space_data(C);
614 ButsContextPath *path= sbuts->path;
618 if(sbuts->flag & SB_PIN_CONTEXT) {
620 for(a=path->len-1; a>=0; a--) {
624 sbuts->pinid= ptr->id.data;
633 ED_area_tag_redraw(CTX_wm_area(C));
636 void buttons_context_draw(const bContext *C, uiLayout *layout)
638 SpaceButs *sbuts= (SpaceButs*)CTX_wm_space_data(C);
639 ButsContextPath *path= sbuts->path;
644 PropertyRNA *nameprop;
645 char namebuf[128], *name;
651 row= uiLayoutRow(layout, 0);
652 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
654 block= uiLayoutGetBlock(row);
655 uiBlockSetEmboss(block, UI_EMBOSSN);
656 but= uiDefIconButBitC(block, ICONTOG, SB_PIN_CONTEXT, 0, (sbuts->flag & SB_PIN_CONTEXT)? ICON_PINNED: ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag, 0, 0, 0, 0, "Follow context or keep fixed datablock displayed.");
657 uiButSetFunc(but, pin_cb, NULL, NULL);
659 for(a=0; a<path->len; a++) {
663 icon= RNA_struct_ui_icon(ptr->type);
664 nameprop= RNA_struct_name_property(ptr->type);
667 if(sbuts->mainb != BCONTEXT_SCENE && ptr->type == &RNA_Scene) {
668 uiItemL(row, "", icon); /* save some space */
673 name= RNA_property_string_get_alloc(ptr, nameprop, namebuf, sizeof(namebuf));
675 uiItemL(row, name, icon);
681 uiItemL(row, "", icon);
686 static void buttons_panel_context(const bContext *C, Panel *pa)
688 buttons_context_draw(C, pa->layout);
691 void buttons_context_register(ARegionType *art)
695 pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
696 strcpy(pt->idname, "BUTTONS_PT_context");
697 strcpy(pt->label, "Context");
698 pt->draw= buttons_panel_context;
699 BLI_addtail(&art->paneltypes, pt);