style cleanup: follow style guide for formatting of if/for/while loops, and else...
[blender.git] / source / blender / editors / space_buttons / buttons_context.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_buttons/buttons_context.c
27  *  \ingroup spbuttons
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_listbase.h"
37 #include "BLI_utildefines.h"
38
39 #include "DNA_armature_types.h"
40 #include "DNA_lamp_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_node_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_world_types.h"
45 #include "DNA_speaker_types.h"
46 #include "DNA_brush_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_action.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_texture.h"
56
57 #include "RNA_access.h"
58
59 #include "ED_armature.h"
60 #include "ED_screen.h"
61 #include "ED_physics.h"
62
63 #include "UI_interface.h"
64 #include "UI_resources.h"
65
66 #include "buttons_intern.h"     // own include
67
68 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
69 {
70         PointerRNA *ptr;
71         int a;
72
73         for (a=0; a<path->len; a++) {
74                 ptr= &path->ptr[a];
75
76                 if (RNA_struct_is_a(ptr->type, type)) {
77                         CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
78                         return 1;
79                 }
80         }
81
82         return 0;
83 }
84
85 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
86 {
87         PointerRNA *ptr;
88         int a;
89
90         for (a=0; a<path->len; a++) {
91                 ptr= &path->ptr[a];
92
93                 if (RNA_struct_is_a(ptr->type, type))
94                         return ptr;
95         }
96
97         return NULL;
98 }
99
100 /************************* Creating the Path ************************/
101
102 static int buttons_context_path_scene(ButsContextPath *path)
103 {
104         PointerRNA *ptr= &path->ptr[path->len-1];
105
106         /* this one just verifies */
107         return RNA_struct_is_a(ptr->type, &RNA_Scene);
108 }
109
110 /* note: this function can return 1 without adding a world to the path
111  * so the buttons stay visible, but be sure to check the ID type if a ID_WO */
112 static int buttons_context_path_world(ButsContextPath *path)
113 {
114         Scene *scene;
115         World *world;
116         PointerRNA *ptr= &path->ptr[path->len-1];
117
118         /* if we already have a (pinned) world, we're done */
119         if (RNA_struct_is_a(ptr->type, &RNA_World)) {
120                 return 1;
121         }
122         /* if we have a scene, use the scene's world */
123         else if (buttons_context_path_scene(path)) {
124                 scene= path->ptr[path->len-1].data;
125                 world= scene->world;
126                 
127                 if (world) {
128                         RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
129                         path->len++;
130                         return 1;
131                 }
132                 else {
133                         return 1;
134                 }
135         }
136
137         /* no path to a world possible */
138         return 0;
139 }
140
141
142 static int buttons_context_path_object(ButsContextPath *path)
143 {
144         Scene *scene;
145         Object *ob;
146         PointerRNA *ptr= &path->ptr[path->len-1];
147
148         /* if we already have a (pinned) object, we're done */
149         if (RNA_struct_is_a(ptr->type, &RNA_Object)) {
150                 return 1;
151         }
152         /* if we have a scene, use the scene's active object */
153         else if (buttons_context_path_scene(path)) {
154                 scene= path->ptr[path->len-1].data;
155                 ob= (scene->basact)? scene->basact->object: NULL;
156
157                 if (ob) {
158                         RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
159                         path->len++;
160
161                         return 1;
162                 }
163         }
164
165         /* no path to a object possible */
166         return 0;
167 }
168
169 static int buttons_context_path_data(ButsContextPath *path, int type)
170 {
171         Object *ob;
172         PointerRNA *ptr= &path->ptr[path->len-1];
173
174         /* if we already have a data, we're done */
175         if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
176         else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
177         else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
178         else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
179         else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
180         else if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
181         else if (RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
182         else if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1;
183         /* try to get an object in the path, no pinning supported here */
184         else if (buttons_context_path_object(path)) {
185                 ob= path->ptr[path->len-1].data;
186
187                 if (ob && (type == -1 || type == ob->type)) {
188                         RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
189                         path->len++;
190
191                         return 1;
192                 }
193         }
194
195         /* no path to data possible */
196         return 0;
197 }
198
199 static int buttons_context_path_modifier(ButsContextPath *path)
200 {
201         Object *ob;
202
203         if (buttons_context_path_object(path)) {
204                 ob= path->ptr[path->len-1].data;
205
206                 if (ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
207                         return 1;
208         }
209
210         return 0;
211 }
212
213 static int buttons_context_path_material(ButsContextPath *path, int for_texture)
214 {
215         Object *ob;
216         PointerRNA *ptr= &path->ptr[path->len-1];
217         Material *ma;
218
219         /* if we already have a (pinned) material, we're done */
220         if (RNA_struct_is_a(ptr->type, &RNA_Material)) {
221                 return 1;
222         }
223         /* if we have an object, use the object material slot */
224         else if (buttons_context_path_object(path)) {
225                 ob= path->ptr[path->len-1].data;
226
227                 if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
228                         ma= give_current_material(ob, ob->actcol);
229                         RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
230                         path->len++;
231
232                         if (for_texture && give_current_material_texture_node(ma))
233                                 return 1;
234                         
235                         ma= give_node_material(ma);
236                         if (ma) {
237                                 RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
238                                 path->len++;
239                         }                       
240                         return 1;
241                 }
242         }
243
244         /* no path to a material possible */
245         return 0;
246 }
247
248 static int buttons_context_path_bone(ButsContextPath *path)
249 {
250         bArmature *arm;
251         EditBone *edbo;
252
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
257                 if (arm->edbo) {
258                         if (arm->act_edbone) {
259                                 edbo= arm->act_edbone;
260                                 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
261                                 path->len++;
262                                 return 1;
263                         }
264                 }
265                 else {
266                         if (arm->act_bone) {
267                                 RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
268                                 path->len++;
269                                 return 1;
270                         }
271                 }
272         }
273
274         /* no path to a bone possible */
275         return 0;
276 }
277
278 static int buttons_context_path_pose_bone(ButsContextPath *path)
279 {
280         PointerRNA *ptr= &path->ptr[path->len-1];
281
282         /* if we already have a (pinned) PoseBone, we're done */
283         if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
284                 return 1;
285         }
286
287         /* if we have an armature, get the active bone */
288         if (buttons_context_path_object(path)) {
289                 Object *ob= path->ptr[path->len-1].data;
290                 bArmature *arm= ob->data; /* path->ptr[path->len-1].data - works too */
291
292                 if (ob->type != OB_ARMATURE || arm->edbo) {
293                         return 0;
294                 }
295                 else {
296                         if (arm->act_bone) {
297                                 bPoseChannel *pchan= get_pose_channel(ob->pose, arm->act_bone->name);
298                                 if (pchan) {
299                                         RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
300                                         path->len++;
301                                         return 1;
302                                 }
303                         }
304                 }
305         }
306
307         /* no path to a bone possible */
308         return 0;
309 }
310
311
312 static int buttons_context_path_particle(ButsContextPath *path)
313 {
314         Object *ob;
315         ParticleSystem *psys;
316         PointerRNA *ptr= &path->ptr[path->len-1];
317
318         /* if we already have (pinned) particle settings, we're done */
319         if (RNA_struct_is_a(ptr->type, &RNA_ParticleSettings)) {
320                 return 1;
321         }
322         /* if we have an object, get the active particle system */
323         if (buttons_context_path_object(path)) {
324                 ob= path->ptr[path->len-1].data;
325
326                 if (ob && ob->type == OB_MESH) {
327                         psys= psys_get_current(ob);
328
329                         RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
330                         path->len++;
331                         return 1;
332                 }
333         }
334
335         /* no path to a particle system possible */
336         return 0;
337 }
338
339 static int buttons_context_path_brush(ButsContextPath *path)
340 {
341         Scene *scene;
342         Brush *br= NULL;
343         PointerRNA *ptr= &path->ptr[path->len-1];
344
345         /* if we already have a (pinned) brush, we're done */
346         if (RNA_struct_is_a(ptr->type, &RNA_Brush)) {
347                 return 1;
348         }
349         /* if we have a scene, use the toolsettings brushes */
350         else if (buttons_context_path_scene(path)) {
351                 scene= path->ptr[path->len-1].data;
352
353                 if (scene)
354                         br= paint_brush(paint_get_active(scene));
355
356                 if (br) {
357                         RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
358                         path->len++;
359
360                         return 1;
361                 }
362         }
363
364         /* no path to a brush possible */
365         return 0;
366 }
367
368 static int buttons_context_path_texture(ButsContextPath *path, ButsContextTexture *ct)
369 {
370         if (ct) {
371                 /* new shading system */
372                 PointerRNA *ptr= &path->ptr[path->len-1];
373                 ID *id;
374
375                 /* if we already have a (pinned) texture, we're done */
376                 if (RNA_struct_is_a(ptr->type, &RNA_Texture))
377                         return 1;
378
379                 if (!ct->user)
380                         return 0;
381                 
382                 id= ct->user->id;
383
384                 if (id) {
385                         if (GS(id->name) == ID_BR)
386                                 buttons_context_path_brush(path);
387                         else if (GS(id->name) == ID_MA)
388                                 buttons_context_path_material(path, 0);
389                         else if (GS(id->name) == ID_WO)
390                                 buttons_context_path_world(path);
391                         else if (GS(id->name) == ID_LA)
392                                 buttons_context_path_data(path, OB_LAMP);
393                         else if (GS(id->name) == ID_PA)
394                                 buttons_context_path_particle(path);
395                         else if (GS(id->name) == ID_OB)
396                                 buttons_context_path_object(path);
397                 }
398                 
399                 if (ct->texture) {
400                         RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
401                         path->len++;
402                 }
403
404                 return 1;
405         }
406         else {
407                 /* old shading system */
408                 Material *ma;
409                 Lamp *la;
410                 Brush *br;
411                 World *wo;
412                 ParticleSystem *psys;
413                 Tex *tex;
414                 PointerRNA *ptr= &path->ptr[path->len-1];
415                 int orig_len = path->len;
416
417                 /* if we already have a (pinned) texture, we're done */
418                 if (RNA_struct_is_a(ptr->type, &RNA_Texture)) {
419                         return 1;
420                 }
421                 /* try brush */
422                 if ((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
423                         br= path->ptr[path->len-1].data;
424                         
425                         if (br) {
426                                 tex= give_current_brush_texture(br);
427
428                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
429                                 path->len++;
430                                 return 1;
431                         }
432                 }
433                 /* try world */
434                 if ((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
435                         wo= path->ptr[path->len-1].data;
436
437                         if (wo && GS(wo->id.name)==ID_WO) {
438                                 tex= give_current_world_texture(wo);
439
440                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
441                                 path->len++;
442                                 return 1;
443                         }
444                 }
445                 /* try particles */
446                 if ((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
447                         if (path->ptr[path->len-1].type == &RNA_ParticleSettings) {
448                                 ParticleSettings *part = path->ptr[path->len-1].data;
449
450                                 tex= give_current_particle_texture(part);
451                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
452                                 path->len++;
453                                 return 1;
454                         }
455                         else {
456                                 psys= path->ptr[path->len-1].data;
457
458                                 if (psys && psys->part && GS(psys->part->id.name)==ID_PA) {
459                                         tex= give_current_particle_texture(psys->part);
460
461                                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
462                                         path->len++;
463                                         return 1;
464                                 }
465                         }
466                 }
467                 /* try material */
468                 if (buttons_context_path_material(path, 1)) {
469                         ma= path->ptr[path->len-1].data;
470
471                         if (ma) {
472                                 tex= give_current_material_texture(ma);
473
474                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
475                                 path->len++;
476                                 return 1;
477                         }
478                 }
479                 /* try lamp */
480                 if (buttons_context_path_data(path, OB_LAMP)) {
481                         la= path->ptr[path->len-1].data;
482
483                         if (la) {
484                                 tex= give_current_lamp_texture(la);
485
486                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
487                                 path->len++;
488                                 return 1;
489                         }
490                 }
491                 /* try brushes again in case of no material, lamp, etc */
492                 path->len = orig_len;
493                 if (buttons_context_path_brush(path)) {
494                         br= path->ptr[path->len-1].data;
495                         
496                         if (br) {
497                                 tex= give_current_brush_texture(br);
498                                 
499                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
500                                 path->len++;
501                                 return 1;
502                         }
503                 }
504         }
505
506         /* no path to a texture possible */
507         return 0;
508 }
509
510
511 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
512 {
513         SpaceButs *sbuts= CTX_wm_space_buts(C);
514         ID *id;
515         int found;
516
517         memset(path, 0, sizeof(*path));
518         path->flag= flag;
519         path->tex_ctx = sbuts->texture_context;
520
521         /* if some ID datablock is pinned, set the root pointer */
522         if (sbuts->pinid) {
523                 id= sbuts->pinid;
524
525                 RNA_id_pointer_create(id, &path->ptr[0]);
526                 path->len++;
527         }
528
529         /* no pinned root, use scene as root */
530         if (path->len == 0) {
531                 id= (ID*)CTX_data_scene(C);
532                 RNA_id_pointer_create(id, &path->ptr[0]);
533                 path->len++;
534         }
535
536         /* now for each buttons context type, we try to construct a path,
537          * tracing back recursively */
538         switch(mainb) {
539                 case BCONTEXT_SCENE:
540                 case BCONTEXT_RENDER:
541                         found= buttons_context_path_scene(path);
542                         break;
543                 case BCONTEXT_WORLD:
544                         found= buttons_context_path_world(path);
545                         break;
546                 case BCONTEXT_OBJECT:
547                 case BCONTEXT_PHYSICS:
548                 case BCONTEXT_CONSTRAINT:
549                         found= buttons_context_path_object(path);
550                         break;
551                 case BCONTEXT_MODIFIER:
552                         found= buttons_context_path_modifier(path);
553                         break;
554                 case BCONTEXT_DATA:
555                         found= buttons_context_path_data(path, -1);
556                         break;
557                 case BCONTEXT_PARTICLE:
558                         found= buttons_context_path_particle(path);
559                         break;
560                 case BCONTEXT_MATERIAL:
561                         found= buttons_context_path_material(path, 0);
562                         break;
563                 case BCONTEXT_TEXTURE:
564                         found= buttons_context_path_texture(path, sbuts->texuser);
565                         break;
566                 case BCONTEXT_BONE:
567                         found= buttons_context_path_bone(path);
568                         if (!found)
569                                 found= buttons_context_path_data(path, OB_ARMATURE);
570                         break;
571                 case BCONTEXT_BONE_CONSTRAINT:
572                         found= buttons_context_path_pose_bone(path);
573                         break;
574                 default:
575                         found= 0;
576                         break;
577         }
578
579         return found;
580 }
581
582 static int buttons_shading_context(const bContext *C, int mainb)
583 {
584         Object *ob= CTX_data_active_object(C);
585
586         if (ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
587                 return 1;
588         if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
589                 return 1;
590         
591         return 0;
592 }
593
594 static int buttons_shading_new_context(const bContext *C, int flag)
595 {
596         Object *ob= CTX_data_active_object(C);
597
598         if (flag & (1 << BCONTEXT_MATERIAL))
599                 return BCONTEXT_MATERIAL;
600         else if (ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA)))
601                 return BCONTEXT_DATA;
602         else if (flag & (1 << BCONTEXT_WORLD))
603                 return BCONTEXT_WORLD;
604         
605         return BCONTEXT_RENDER;
606 }
607
608 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
609 {
610         ButsContextPath *path;
611         PointerRNA *ptr;
612         int a, pflag= 0, flag= 0;
613
614         buttons_texture_context_compute(C, sbuts);
615
616         if (!sbuts->path)
617                 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
618         
619         path= sbuts->path;
620         
621         /* for each context, see if we can compute a valid path to it, if
622          * this is the case, we know we have to display the button */
623         for (a=0; a<BCONTEXT_TOT; a++) {
624                 if (buttons_context_path(C, path, a, pflag)) {
625                         flag |= (1<<a);
626
627                         /* setting icon for data context */
628                         if (a == BCONTEXT_DATA) {
629                                 ptr= &path->ptr[path->len-1];
630
631                                 if (ptr->type)
632                                         sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
633                                 else
634                                         sbuts->dataicon= ICON_EMPTY_DATA;
635                         }
636                 }
637         }
638
639         /* always try to use the tab that was explicitly
640          * set to the user, so that once that context comes
641          * back, the tab is activated again */
642         sbuts->mainb= sbuts->mainbuser;
643
644         /* in case something becomes invalid, change */
645         if ((flag & (1 << sbuts->mainb)) == 0) {
646                 if (sbuts->flag & SB_SHADING_CONTEXT) {
647                         /* try to keep showing shading related buttons */
648                         sbuts->mainb= buttons_shading_new_context(C, flag);
649                 }
650                 else if (flag & BCONTEXT_OBJECT) {
651                         sbuts->mainb= BCONTEXT_OBJECT;
652                 }
653                 else {
654                         for (a=0; a<BCONTEXT_TOT; a++) {
655                                 if (flag & (1 << a)) {
656                                         sbuts->mainb= a;
657                                         break;
658                                 }
659                         }
660                 }
661         }
662
663         buttons_context_path(C, path, sbuts->mainb, pflag);
664
665         if (!(flag & (1 << sbuts->mainb))) {
666                 if (flag & (1 << BCONTEXT_OBJECT))
667                         sbuts->mainb= BCONTEXT_OBJECT;
668                 else
669                         sbuts->mainb= BCONTEXT_SCENE;
670         }
671
672         if (buttons_shading_context(C, sbuts->mainb))
673                 sbuts->flag |= SB_SHADING_CONTEXT;
674         else
675                 sbuts->flag &= ~SB_SHADING_CONTEXT;
676
677         sbuts->pathflag= flag;
678 }
679
680 /************************* Context Callback ************************/
681
682 const char *buttons_context_dir[] = {
683         "world", "object", "mesh", "armature", "lattice", "curve",
684         "meta_ball", "lamp", "speaker", "camera", "material", "material_slot",
685         "texture", "texture_slot", "texture_user", "bone", "edit_bone",
686         "pose_bone", "particle_system", "particle_system_editable",
687         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint", NULL};
688
689 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
690 {
691         SpaceButs *sbuts= CTX_wm_space_buts(C);
692         ButsContextPath *path= sbuts?sbuts->path:NULL;
693
694         if (!path)
695                 return 0;
696
697         /* here we handle context, getting data from precomputed path */
698         if (CTX_data_dir(member)) {
699                 CTX_data_dir_set(result, buttons_context_dir);
700                 return 1;
701         }
702         else if (CTX_data_equals(member, "world")) {
703                 set_pointer_type(path, result, &RNA_World);
704                 return 1;
705         }
706         else if (CTX_data_equals(member, "object")) {
707                 set_pointer_type(path, result, &RNA_Object);
708                 return 1;
709         }
710         else if (CTX_data_equals(member, "mesh")) {
711                 set_pointer_type(path, result, &RNA_Mesh);
712                 return 1;
713         }
714         else if (CTX_data_equals(member, "armature")) {
715                 set_pointer_type(path, result, &RNA_Armature);
716                 return 1;
717         }
718         else if (CTX_data_equals(member, "lattice")) {
719                 set_pointer_type(path, result, &RNA_Lattice);
720                 return 1;
721         }
722         else if (CTX_data_equals(member, "curve")) {
723                 set_pointer_type(path, result, &RNA_Curve);
724                 return 1;
725         }
726         else if (CTX_data_equals(member, "meta_ball")) {
727                 set_pointer_type(path, result, &RNA_MetaBall);
728                 return 1;
729         }
730         else if (CTX_data_equals(member, "lamp")) {
731                 set_pointer_type(path, result, &RNA_Lamp);
732                 return 1;
733         }
734         else if (CTX_data_equals(member, "camera")) {
735                 set_pointer_type(path, result, &RNA_Camera);
736                 return 1;
737         }
738         else if (CTX_data_equals(member, "speaker")) {
739                 set_pointer_type(path, result, &RNA_Speaker);
740                 return 1;
741         }
742         else if (CTX_data_equals(member, "material")) {
743                 set_pointer_type(path, result, &RNA_Material);
744                 return 1;
745         }
746         else if (CTX_data_equals(member, "texture")) {
747                 ButsContextTexture *ct= sbuts->texuser;
748
749                 if (ct) {
750                         /* new shading system */
751                         CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
752                 }
753                 else {
754                         /* old shading system */
755                         set_pointer_type(path, result, &RNA_Texture);
756                 }
757
758                 return 1;
759         }
760         else if (CTX_data_equals(member, "material_slot")) {
761                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
762
763                 if (ptr) {
764                         Object *ob= ptr->data;
765
766                         if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) {
767                                 /* a valid actcol isn't ensured [#27526] */
768                                 int matnr= ob->actcol-1;
769                                 if (matnr < 0) matnr= 0;
770                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]);
771                         }
772                 }
773
774                 return 1;
775         }
776         else if (CTX_data_equals(member, "texture_user")) {
777                 ButsContextTexture *ct= sbuts->texuser;
778
779                 if (!ct)
780                         return -1; /* old shading system (found but not available) */
781
782                 if (ct->user && ct->user->ptr.data) {
783                         ButsTextureUser *user= ct->user; 
784                         CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data);
785                 }
786
787                 return 1;
788         }
789         else if (CTX_data_equals(member, "texture_node")) {
790                 ButsContextTexture *ct= sbuts->texuser;
791
792                 if (ct) {
793                         /* new shading system */
794                         if (ct->user && ct->user->node)
795                                 CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node);
796
797                         return 1;
798                 }
799                 else {
800                         /* old shading system */
801                         PointerRNA *ptr;
802
803                         if ((ptr=get_pointer_type(path, &RNA_Material))) {
804                                 Material *ma= ptr->data;
805
806                                 if (ma) {
807                                         bNode *node= give_current_material_texture_node(ma);
808                                         CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node);
809                                 }
810                         }
811
812                         return 1;
813                 }
814         }
815         else if (CTX_data_equals(member, "texture_slot")) {
816                 ButsContextTexture *ct= sbuts->texuser;
817                 PointerRNA *ptr;
818
819                 if (ct)
820                         return 0; /* new shading system */
821
822                 if ((ptr=get_pointer_type(path, &RNA_Material))) {
823                         Material *ma= ptr->data;
824
825                         /* if we have a node material, get slot from material in material node */
826                         if (ma && ma->use_nodes && ma->nodetree) {
827                                 /* if there's an active texture node in the node tree,
828                                  * then that texture is in context directly, without a texture slot */
829                                 if (give_current_material_texture_node(ma))
830                                         return 0;
831                                 
832                                 ma= give_node_material(ma);
833                                 if (ma)
834                                         CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
835                                 else
836                                         return 0;
837                         }
838                         else if (ma) {
839                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
840                         }
841                 }
842                 else if ((ptr=get_pointer_type(path, &RNA_Lamp))) {
843                         Lamp *la= ptr->data;
844
845                         if (la)
846                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
847                 }
848                 else if ((ptr=get_pointer_type(path, &RNA_World))) {
849                         World *wo= ptr->data;
850
851                         if (wo)
852                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
853                 }
854                 else if ((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
855                         Brush *br= ptr->data;
856
857                         if (br)
858                                 CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
859                 }
860                 else if ((ptr=get_pointer_type(path, &RNA_ParticleSystem))) {
861                         ParticleSettings *part= ((ParticleSystem *)ptr->data)->part;
862
863                         if (part)
864                                 CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
865                 }
866
867                 return 1;
868         }
869         else if (CTX_data_equals(member, "bone")) {
870                 set_pointer_type(path, result, &RNA_Bone);
871                 return 1;
872         }
873         else if (CTX_data_equals(member, "edit_bone")) {
874                 set_pointer_type(path, result, &RNA_EditBone);
875                 return 1;
876         }
877         else if (CTX_data_equals(member, "pose_bone")) {
878                 set_pointer_type(path, result, &RNA_PoseBone);
879                 return 1;
880         }
881         else if (CTX_data_equals(member, "particle_system")) {
882                 set_pointer_type(path, result, &RNA_ParticleSystem);
883                 return 1;
884         }
885         else if (CTX_data_equals(member, "particle_system_editable")) {
886                 if (PE_poll((bContext*)C))
887                         set_pointer_type(path, result, &RNA_ParticleSystem);
888                 else
889                         CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
890                 return 1;
891         }       
892         else if (CTX_data_equals(member, "cloth")) {
893                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
894
895                 if (ptr && ptr->data) {
896                         Object *ob= ptr->data;
897                         ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
898                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
899                         return 1;
900                 }
901         }
902         else if (CTX_data_equals(member, "soft_body")) {
903                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
904
905                 if (ptr && ptr->data) {
906                         Object *ob= ptr->data;
907                         ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
908                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
909                         return 1;
910                 }
911         }
912         else if (CTX_data_equals(member, "fluid")) {
913                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
914
915                 if (ptr && ptr->data) {
916                         Object *ob= ptr->data;
917                         ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
918                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
919                         return 1;
920                 }
921         }
922         
923         else if (CTX_data_equals(member, "smoke")) {
924                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
925
926                 if (ptr && ptr->data) {
927                         Object *ob= ptr->data;
928                         ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
929                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
930                         return 1;
931                 }
932         }
933         else if (CTX_data_equals(member, "collision")) {
934                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
935
936                 if (ptr && ptr->data) {
937                         Object *ob= ptr->data;
938                         ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
939                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
940                         return 1;
941                 }
942         }
943         else if (CTX_data_equals(member, "brush")) {
944                 set_pointer_type(path, result, &RNA_Brush);
945                 return 1;
946         }
947         else if (CTX_data_equals(member, "dynamic_paint")) {
948                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
949
950                 if (ptr && ptr->data) {
951                         Object *ob= ptr->data;
952                         ModifierData *md= modifiers_findByType(ob, eModifierType_DynamicPaint);
953                         CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
954                         return 1;
955                 }
956         }
957         else {
958                 return 0; /* not found */
959         }
960
961         return -1; /* found but not available */
962 }
963
964 /************************* Drawing the Path ************************/
965
966 static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
967 {
968         SpaceButs *sbuts= CTX_wm_space_buts(C);
969
970         if (sbuts->flag & SB_PIN_CONTEXT) {
971                 sbuts->pinid= buttons_context_id_path(C);
972         }
973         else
974                 sbuts->pinid= NULL;
975         
976         ED_area_tag_redraw(CTX_wm_area(C));
977 }
978
979 void buttons_context_draw(const bContext *C, uiLayout *layout)
980 {
981         SpaceButs *sbuts= CTX_wm_space_buts(C);
982         ButsContextPath *path= sbuts->path;
983         uiLayout *row;
984         uiBlock *block;
985         uiBut *but;
986         PointerRNA *ptr;
987         char namebuf[128], *name;
988         int a, icon;
989
990         if (!path)
991                 return;
992
993         row= uiLayoutRow(layout, 1);
994         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
995
996         block= uiLayoutGetBlock(row);
997         uiBlockSetEmboss(block, UI_EMBOSSN);
998         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");
999         uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
1000         uiButSetFunc(but, pin_cb, NULL, NULL);
1001
1002         for (a=0; a<path->len; a++) {
1003                 ptr= &path->ptr[a];
1004
1005                 if (a != 0)
1006                         uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
1007
1008                 if (ptr->data) {
1009                         icon= RNA_struct_ui_icon(ptr->type);
1010                         name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
1011
1012                         if (name) {
1013                                 if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
1014                                         uiItemLDrag(row, ptr, "", icon); /* save some space */
1015                                 else
1016                                         uiItemLDrag(row, ptr, name, icon);
1017                                                                  
1018                                 if (name != namebuf)
1019                                         MEM_freeN(name);
1020                         }
1021                         else
1022                                 uiItemL(row, "", icon);
1023                 }
1024         }
1025 }
1026
1027 static void buttons_panel_context(const bContext *C, Panel *pa)
1028 {
1029         buttons_context_draw(C, pa->layout);
1030 }
1031
1032 void buttons_context_register(ARegionType *art)
1033 {
1034         PanelType *pt;
1035
1036         pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
1037         strcpy(pt->idname, "BUTTONS_PT_context");
1038         strcpy(pt->label, "Context");
1039         pt->draw= buttons_panel_context;
1040         pt->flag= PNL_NO_HEADER;
1041         BLI_addtail(&art->paneltypes, pt);
1042 }
1043
1044 ID *buttons_context_id_path(const bContext *C)
1045 {
1046         SpaceButs *sbuts= CTX_wm_space_buts(C);
1047         ButsContextPath *path= sbuts->path;
1048         PointerRNA *ptr;
1049         int a;
1050
1051         if (path->len) {
1052                 for (a=path->len-1; a>=0; a--) {
1053                         ptr= &path->ptr[a];
1054
1055                         /* pin particle settings instead of system, since only settings are an idblock*/
1056                         if (sbuts->mainb == BCONTEXT_PARTICLE && sbuts->flag & SB_PIN_CONTEXT) {
1057                                 if (ptr->type == &RNA_ParticleSystem && ptr->data) {
1058                                         ParticleSystem *psys = (ParticleSystem *)ptr->data;
1059                                         return &psys->part->id;
1060                                 }
1061                         }
1062
1063                         if (ptr->id.data) {
1064                                 return ptr->id.data;
1065                         }
1066                 }
1067         }
1068
1069         return NULL;
1070 }