ad65177650fbd02b2d26a0e651500a6ff6441319
[blender-staging.git] / source / blender / editors / space_buttons / buttons_context.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
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"
45
46 #include "BLI_listbase.h"
47
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"
56
57 #include "RNA_access.h"
58
59 #include "ED_armature.h"
60 #include "ED_screen.h"
61
62 #include "UI_interface.h"
63 #include "UI_resources.h"
64
65 #include "buttons_intern.h"     // own include
66
67 typedef struct ButsContextPath {
68         PointerRNA ptr[8];
69         int len;
70         int flag;
71 } ButsContextPath;
72
73 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
74 {
75         PointerRNA *ptr;
76         int a;
77
78         for(a=0; a<path->len; a++) {
79                 ptr= &path->ptr[a];
80
81                 if(RNA_struct_is_a(ptr->type, type)) {
82                         CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
83                         return 1;
84                 }
85         }
86
87         return 0;
88 }
89
90 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
91 {
92         PointerRNA *ptr;
93         int a;
94
95         for(a=0; a<path->len; a++) {
96                 ptr= &path->ptr[a];
97
98                 if(RNA_struct_is_a(ptr->type, type))
99                         return ptr;
100         }
101
102         return NULL;
103 }
104
105 /************************* Creating the Path ************************/
106
107 static int buttons_context_path_scene(ButsContextPath *path)
108 {
109         PointerRNA *ptr= &path->ptr[path->len-1];
110
111         /* this one just verifies */
112         return RNA_struct_is_a(ptr->type, &RNA_Scene);
113 }
114
115 static int buttons_context_path_world(ButsContextPath *path)
116 {
117         Scene *scene;
118         PointerRNA *ptr= &path->ptr[path->len-1];
119
120         /* if we already have a (pinned) world, we're done */
121         if(RNA_struct_is_a(ptr->type, &RNA_World)) {
122                 return 1;
123         }
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;
127
128                 RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
129                 path->len++;
130
131                 return 1;
132         }
133
134         /* no path to a world possible */
135         return 0;
136 }
137
138
139 static int buttons_context_path_object(ButsContextPath *path)
140 {
141         Scene *scene;
142         Object *ob;
143         PointerRNA *ptr= &path->ptr[path->len-1];
144
145         /* if we already have a (pinned) object, we're done */
146         if(RNA_struct_is_a(ptr->type, &RNA_Object)) {
147                 return 1;
148         }
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;
153
154                 if(ob) {
155                         RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
156                         path->len++;
157
158                         return 1;
159                 }
160         }
161
162         /* no path to a object possible */
163         return 0;
164 }
165
166 static int buttons_context_path_data(ButsContextPath *path, int type)
167 {
168         Object *ob;
169         PointerRNA *ptr= &path->ptr[path->len-1];
170
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;
182
183                 if(ob && (type == -1 || type == ob->type)) {
184                         RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
185                         path->len++;
186
187                         return 1;
188                 }
189         }
190
191         /* no path to data possible */
192         return 0;
193 }
194
195 static int buttons_context_path_modifier(ButsContextPath *path)
196 {
197         Object *ob;
198
199         if(buttons_context_path_object(path)) {
200                 ob= path->ptr[path->len-1].data;
201
202                 if(ob && ELEM4(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF))
203                         return 1;
204         }
205
206         return 0;
207 }
208
209 static int buttons_context_path_material(ButsContextPath *path)
210 {
211         Object *ob;
212         PointerRNA *ptr= &path->ptr[path->len-1];
213         Material *ma;
214
215         /* if we already have a (pinned) material, we're done */
216         if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
217                 return 1;
218         }
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;
222
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]);
226                         path->len++;
227                         return 1;
228                 }
229         }
230
231         /* no path to a material possible */
232         return 0;
233 }
234
235 static Bone *find_active_bone(Bone *bone)
236 {
237         Bone *active;
238
239         for(; bone; bone=bone->next) {
240                 if(bone->flag & BONE_ACTIVE)
241                         return bone;
242
243                 active= find_active_bone(bone->childbase.first);
244                 if(active)
245                         return active;
246         }
247
248         return NULL;
249 }
250
251 static int buttons_context_path_bone(ButsContextPath *path)
252 {
253         bArmature *arm;
254         Bone *bone;
255         EditBone *edbo;
256
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;
260
261                 if(arm->edbo) {
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]);
265                                         path->len++;
266                                         return 1;
267                                 }
268                         }
269                 }
270                 else {
271                         bone= find_active_bone(arm->bonebase.first);
272
273                         if(bone) {
274                                 RNA_pointer_create(&arm->id, &RNA_Bone, bone, &path->ptr[path->len]);
275                                 path->len++;
276                                 return 1;
277                         }
278                 }
279         }
280
281         /* no path to a bone possible */
282         return 0;
283 }
284
285 static int buttons_context_path_particle(ButsContextPath *path)
286 {
287         Object *ob;
288         ParticleSystem *psys;
289
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;
293
294                 if(ob && ob->type == OB_MESH) {
295                         psys= psys_get_current(ob);
296
297                         RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
298                         path->len++;
299                         return 1;
300                 }
301         }
302
303         /* no path to a particle system possible */
304         return 0;
305 }
306
307 static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
308 {
309         Scene *scene;
310         ToolSettings *ts;
311         Brush *br= NULL;
312         PointerRNA *ptr= &path->ptr[path->len-1];
313         const Object *obact = CTX_data_active_object(C);
314
315         /* if we already have a (pinned) brush, we're done */
316         if(RNA_struct_is_a(ptr->type, &RNA_Brush)) {
317                 return 1;
318         }
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;
323
324                 if(obact) {
325                         if(obact->mode & OB_MODE_SCULPT)
326                                 br= ts->sculpt->brush;
327                         else if(obact->mode & OB_MODE_VERTEX_PAINT)
328                                 br= ts->vpaint->brush;
329                         else if(obact->mode & OB_MODE_WEIGHT_PAINT)
330                                 br= ts->wpaint->brush;
331                         else if(obact->mode & OB_MODE_TEXTURE_PAINT)
332                                 br= ts->imapaint.brush;
333                 }
334
335                 if(br) {
336                         RNA_id_pointer_create(&br->id, &path->ptr[path->len]);
337                         path->len++;
338
339                         return 1;
340                 }
341         }
342
343         /* no path to a world possible */
344         return 0;
345 }
346
347 static int buttons_context_path_texture(const bContext *C, ButsContextPath *path)
348 {
349         Material *ma;
350         Lamp *la;
351         Brush *br;
352         World *wo;
353         MTex *mtex;
354         Tex *tex;
355         PointerRNA *ptr= &path->ptr[path->len-1];
356
357         /* if we already have a (pinned) texture, we're done */
358         if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
359                 return 1;
360         }
361         /* try brush */
362         else if((path->flag & SB_BRUSH_TEX) && buttons_context_path_brush(C, path)) {
363                 br= path->ptr[path->len-1].data;
364
365                 if(br) {
366                         mtex= br->mtex[(int)br->texact];
367                         tex= (mtex)? mtex->tex: NULL;
368
369                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
370                         path->len++;
371                         return 1;
372                 }
373         }
374         /* try world */
375         else if((path->flag & SB_WORLD_TEX) && buttons_context_path_world(path)) {
376                 wo= path->ptr[path->len-1].data;
377
378                 if(wo) {
379                         mtex= wo->mtex[(int)wo->texact];
380                         tex= (mtex)? mtex->tex: NULL;
381
382                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
383                         path->len++;
384                         return 1;
385                 }
386         }
387         /* try material */
388         else if(buttons_context_path_material(path)) {
389                 ma= path->ptr[path->len-1].data;
390
391                 if(ma) {
392                         mtex= ma->mtex[(int)ma->texact];
393                         tex= (mtex)? mtex->tex: NULL;
394
395                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
396                         path->len++;
397                         return 1;
398                 }
399         }
400         /* try lamp */
401         else if(buttons_context_path_data(path, OB_LAMP)) {
402                 la= path->ptr[path->len-1].data;
403
404                 if(la) {
405                         mtex= la->mtex[(int)la->texact];
406                         tex= (mtex)? mtex->tex: NULL;
407
408                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
409                         path->len++;
410                         return 1;
411                 }
412         }
413         /* TODO: material nodes */
414
415         /* no path to a texture possible */
416         return 0;
417 }
418
419
420 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
421 {
422         SpaceButs *sbuts= CTX_wm_space_buts(C);
423         ID *id;
424         int found;
425
426         memset(path, 0, sizeof(*path));
427         path->flag= flag;
428
429         /* if some ID datablock is pinned, set the root pointer */
430         if(sbuts->pinid) {
431                 id= sbuts->pinid;
432
433                 RNA_id_pointer_create(id, &path->ptr[0]);
434                 path->len++;
435         }
436
437         /* no pinned root, use scene as root */
438         if(path->len == 0) {
439                 id= (ID*)CTX_data_scene(C);
440                 RNA_id_pointer_create(id, &path->ptr[0]);
441                 path->len++;
442         }
443
444         /* now for each buttons context type, we try to construct a path,
445          * tracing back recursively */
446         switch(mainb) {
447                 case BCONTEXT_SCENE:
448                         found= buttons_context_path_scene(path);
449                         break;
450                 case BCONTEXT_WORLD:
451                         found= buttons_context_path_world(path);
452                         break;
453                 case BCONTEXT_OBJECT:
454                 case BCONTEXT_PHYSICS:
455                 case BCONTEXT_CONSTRAINT:
456                         found= buttons_context_path_object(path);
457                         break;
458                 case BCONTEXT_MODIFIER:
459                         found= buttons_context_path_modifier(path);
460                         break;
461                 case BCONTEXT_DATA:
462                         found= buttons_context_path_data(path, -1);
463                         break;
464                 case BCONTEXT_PARTICLE:
465                         found= buttons_context_path_particle(path);
466                         break;
467                 case BCONTEXT_MATERIAL:
468                         found= buttons_context_path_material(path);
469                         break;
470                 case BCONTEXT_TEXTURE:
471                         found= buttons_context_path_texture(C, path);
472                         break;
473                 case BCONTEXT_BONE:
474                         found= buttons_context_path_bone(path);
475                         if(!found)
476                                 found= buttons_context_path_data(path, OB_ARMATURE);
477                         break;
478                 default:
479                         found= 0;
480                         break;
481         }
482
483         return found;
484 }
485
486 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
487 {
488         ButsContextPath *path;
489         PointerRNA *ptr;
490         int a, pflag, flag= 0;
491
492         if(!sbuts->path)
493                 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
494         
495         path= sbuts->path;
496         pflag= (sbuts->flag & (SB_WORLD_TEX|SB_BRUSH_TEX));
497         
498         /* for each context, see if we can compute a valid path to it, if
499          * this is the case, we know we have to display the button */
500         for(a=0; a<BCONTEXT_TOT; a++) {
501                 if(buttons_context_path(C, path, a, pflag)) {
502                         flag |= (1<<a);
503
504                         /* setting icon for data context */
505                         if(a == BCONTEXT_DATA) {
506                                 ptr= &path->ptr[path->len-1];
507
508                                 if(ptr->type)
509                                         sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
510                                 else
511                                         sbuts->dataicon= ICON_EMPTY_DATA;
512                         }
513                 }
514         }
515
516         /* always try to use the tab that was explicitly
517          * set to the user, so that once that context comes
518          * back, the tab is activated again */
519         sbuts->mainb= sbuts->mainbuser;
520
521         /* in case something becomes invalid, change */
522         if((flag & (1 << sbuts->mainb)) == 0) {
523                 if(flag & BCONTEXT_OBJECT) {
524                         sbuts->mainb= BCONTEXT_OBJECT;
525                 }
526                 else {
527                         for(a=0; a<BCONTEXT_TOT; a++) {
528                                 if(flag & (1 << a)) {
529                                         sbuts->mainb= a;
530                                         break;
531                                 }
532                         }
533                 }
534         }
535
536         buttons_context_path(C, path, sbuts->mainb, pflag);
537
538         if(!(flag & (1 << sbuts->mainb))) {
539                 if(flag & (1 << BCONTEXT_OBJECT))
540                         sbuts->mainb= BCONTEXT_OBJECT;
541                 else
542                         sbuts->mainb= BCONTEXT_SCENE;
543         }
544
545         sbuts->pathflag= flag;
546 }
547
548 /************************* Context Callback ************************/
549
550 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
551 {
552         SpaceButs *sbuts= CTX_wm_space_buts(C);
553         ButsContextPath *path= sbuts?sbuts->path:NULL;
554
555         if(!path)
556                 return 0;
557
558         /* here we handle context, getting data from precomputed path */
559         if(CTX_data_dir(member)) {
560                 static const char *dir[] = {
561                         "world", "object", "mesh", "armature", "lattice", "curve",
562                         "meta_ball", "lamp", "camera", "material", "material_slot",
563                         "texture", "texture_slot", "bone", "edit_bone", "particle_system",
564                         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
565
566                 CTX_data_dir_set(result, dir);
567                 return 1;
568         }
569         else if(CTX_data_equals(member, "world")) {
570                 set_pointer_type(path, result, &RNA_World);
571                 return 1;
572         }
573         else if(CTX_data_equals(member, "object")) {
574                 set_pointer_type(path, result, &RNA_Object);
575                 return 1;
576         }
577         else if(CTX_data_equals(member, "mesh")) {
578                 set_pointer_type(path, result, &RNA_Mesh);
579                 return 1;
580         }
581         else if(CTX_data_equals(member, "armature")) {
582                 set_pointer_type(path, result, &RNA_Armature);
583                 return 1;
584         }
585         else if(CTX_data_equals(member, "lattice")) {
586                 set_pointer_type(path, result, &RNA_Lattice);
587                 return 1;
588         }
589         else if(CTX_data_equals(member, "curve")) {
590                 set_pointer_type(path, result, &RNA_Curve);
591                 return 1;
592         }
593         else if(CTX_data_equals(member, "meta_ball")) {
594                 set_pointer_type(path, result, &RNA_MetaBall);
595                 return 1;
596         }
597         else if(CTX_data_equals(member, "lamp")) {
598                 set_pointer_type(path, result, &RNA_Lamp);
599                 return 1;
600         }
601         else if(CTX_data_equals(member, "camera")) {
602                 set_pointer_type(path, result, &RNA_Camera);
603                 return 1;
604         }
605         else if(CTX_data_equals(member, "material")) {
606                 set_pointer_type(path, result, &RNA_Material);
607                 return 1;
608         }
609         else if(CTX_data_equals(member, "texture")) {
610                 set_pointer_type(path, result, &RNA_Texture);
611                 return 1;
612         }
613         else if(CTX_data_equals(member, "material_slot")) {
614                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
615
616                 if(ptr) {
617                         Object *ob= ptr->data;
618
619                         if(ob && ob->type && (ob->type<OB_LAMP) && ob->totcol)
620                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
621                 }
622
623                 return 1;
624         }
625         else if(CTX_data_equals(member, "texture_slot")) {
626                 PointerRNA *ptr;
627
628                 if((ptr=get_pointer_type(path, &RNA_Material))) {
629                         Material *ma= ptr->data;
630
631                         if(ma)
632                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
633                 }
634                 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
635                         Lamp *la= ptr->data;
636
637                         if(la)
638                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
639                 }
640                 else if((ptr=get_pointer_type(path, &RNA_World))) {
641                         World *wo= ptr->data;
642
643                         if(wo)
644                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
645                 }
646                 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
647                         Brush *br= ptr->data;
648
649                         if(br)
650                                 CTX_data_pointer_set(result, &br->id, &RNA_TextureSlot, br->mtex[(int)br->texact]);
651                 }
652
653                 return 1;
654         }
655         else if(CTX_data_equals(member, "bone")) {
656                 set_pointer_type(path, result, &RNA_Bone);
657                 return 1;
658         }
659         else if(CTX_data_equals(member, "edit_bone")) {
660                 set_pointer_type(path, result, &RNA_EditBone);
661                 return 1;
662         }
663         else if(CTX_data_equals(member, "particle_system")) {
664                 set_pointer_type(path, result, &RNA_ParticleSystem);
665                 return 1;
666         }
667         else if(CTX_data_equals(member, "cloth")) {
668                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
669
670                 if(ptr && ptr->data) {
671                         Object *ob= ptr->data;
672                         ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
673                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
674                         return 1;
675                 }
676         }
677         else if(CTX_data_equals(member, "soft_body")) {
678                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
679
680                 if(ptr && ptr->data) {
681                         Object *ob= ptr->data;
682                         ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
683                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
684                         return 1;
685                 }
686         }
687         else if(CTX_data_equals(member, "fluid")) {
688                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
689
690                 if(ptr && ptr->data) {
691                         Object *ob= ptr->data;
692                         ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
693                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
694                         return 1;
695                 }
696         }
697         
698         else if(CTX_data_equals(member, "smoke")) {
699                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
700
701                 if(ptr && ptr->data) {
702                         Object *ob= ptr->data;
703                         ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
704                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
705                         return 1;
706                 }
707         }
708         else if(CTX_data_equals(member, "collision")) {
709                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
710
711                 if(ptr && ptr->data) {
712                         Object *ob= ptr->data;
713                         ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
714                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
715                         return 1;
716                 }
717         }
718         else if(CTX_data_equals(member, "brush")) {
719                 set_pointer_type(path, result, &RNA_Brush);
720                 return 1;
721         }
722
723         return 0;
724 }
725
726 /************************* Drawing the Path ************************/
727
728 static void pin_cb(bContext *C, void *arg1, void *arg2)
729 {
730         SpaceButs *sbuts= CTX_wm_space_buts(C);
731         ButsContextPath *path= sbuts->path;
732         PointerRNA *ptr;
733         int a;
734
735         if(sbuts->flag & SB_PIN_CONTEXT) {
736                 if(path->len) {
737                         for(a=path->len-1; a>=0; a--) {
738                                 ptr= &path->ptr[a];
739
740                                 if(ptr->id.data) {
741                                         sbuts->pinid= ptr->id.data;
742                                         break;
743                                 }
744                         }
745                 }
746         }
747         else
748                 sbuts->pinid= NULL;
749         
750         ED_area_tag_redraw(CTX_wm_area(C));
751 }
752
753 void buttons_context_draw(const bContext *C, uiLayout *layout)
754 {
755         SpaceButs *sbuts= CTX_wm_space_buts(C);
756         ButsContextPath *path= sbuts->path;
757         uiLayout *row;
758         uiBlock *block;
759         uiBut *but;
760         PointerRNA *ptr;
761         char namebuf[128], *name;
762         int a, icon;
763
764         if(!path)
765                 return;
766
767         row= uiLayoutRow(layout, 1);
768         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
769
770         block= uiLayoutGetBlock(row);
771         uiBlockSetEmboss(block, UI_EMBOSSN);
772         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.");
773         uiButSetFunc(but, pin_cb, NULL, NULL);
774
775         for(a=0; a<path->len; a++) {
776                 ptr= &path->ptr[a];
777
778                 if(a != 0)
779                         uiDefIconBut(block, LABEL, 0, VICON_SMALL_TRI_RIGHT, 0, 0, 10, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
780
781                 if(ptr->data) {
782                         icon= RNA_struct_ui_icon(ptr->type);
783                         name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf));
784
785                         if(name) {
786                                 if(sbuts->mainb != BCONTEXT_SCENE && ptr->type == &RNA_Scene)
787                                         uiItemL(row, "", icon); /* save some space */
788                                 else
789                                         uiItemL(row, name, icon);
790
791                                 if(name != namebuf)
792                                         MEM_freeN(name);
793                         }
794                         else
795                                 uiItemL(row, "", icon);
796                 }
797         }
798 }
799
800 static void buttons_panel_context(const bContext *C, Panel *pa)
801 {
802         buttons_context_draw(C, pa->layout);
803 }
804
805 void buttons_context_register(ARegionType *art)
806 {
807         PanelType *pt;
808
809         pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
810         strcpy(pt->idname, "BUTTONS_PT_context");
811         strcpy(pt->label, "Context");
812         pt->draw= buttons_panel_context;
813         pt->flag= PNL_NO_HEADER;
814         BLI_addtail(&art->paneltypes, pt);
815 }