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