Fix build error on Windows 32 bit.
[blender-staging.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 "BLT_translation.h"
40
41 #include "DNA_armature_types.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_world_types.h"
47 #include "DNA_brush_types.h"
48 #include "DNA_linestyle_types.h"
49
50 #include "BKE_context.h"
51 #include "BKE_action.h"
52 #include "BKE_material.h"
53 #include "BKE_modifier.h"
54 #include "BKE_paint.h"
55 #include "BKE_particle.h"
56 #include "BKE_screen.h"
57 #include "BKE_texture.h"
58 #include "BKE_linestyle.h"
59
60 #include "RNA_access.h"
61
62 #include "ED_buttons.h"
63 #include "ED_armature.h"
64 #include "ED_screen.h"
65 #include "ED_physics.h"
66
67 #include "UI_interface.h"
68 #include "UI_resources.h"
69
70 #include "buttons_intern.h" // own include
71
72 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
73 {
74         PointerRNA *ptr;
75         int a;
76
77         for (a = 0; a < path->len; a++) {
78                 ptr = &path->ptr[a];
79
80                 if (RNA_struct_is_a(ptr->type, type)) {
81                         CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
82                         return 1;
83                 }
84         }
85
86         return 0;
87 }
88
89 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
90 {
91         PointerRNA *ptr;
92         int a;
93
94         for (a = 0; a < path->len; a++) {
95                 ptr = &path->ptr[a];
96
97                 if (RNA_struct_is_a(ptr->type, type))
98                         return ptr;
99         }
100
101         return NULL;
102 }
103
104 /************************* Creating the Path ************************/
105
106 static int buttons_context_path_scene(ButsContextPath *path)
107 {
108         PointerRNA *ptr = &path->ptr[path->len - 1];
109
110         /* this one just verifies */
111         return RNA_struct_is_a(ptr->type, &RNA_Scene);
112 }
113
114 /* note: this function can return 1 without adding a world to the path
115  * so the buttons stay visible, but be sure to check the ID type if a ID_WO */
116 static int buttons_context_path_world(ButsContextPath *path)
117 {
118         Scene *scene;
119         World *world;
120         PointerRNA *ptr = &path->ptr[path->len - 1];
121
122         /* if we already have a (pinned) world, we're done */
123         if (RNA_struct_is_a(ptr->type, &RNA_World)) {
124                 return 1;
125         }
126         /* if we have a scene, use the scene's world */
127         else if (buttons_context_path_scene(path)) {
128                 scene = path->ptr[path->len - 1].data;
129                 world = scene->world;
130                 
131                 if (world) {
132                         RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
133                         path->len++;
134                         return 1;
135                 }
136                 else {
137                         return 1;
138                 }
139         }
140
141         /* no path to a world possible */
142         return 0;
143 }
144
145 static int buttons_context_path_linestyle(ButsContextPath *path)
146 {
147         Scene *scene;
148         FreestyleLineStyle *linestyle;
149         PointerRNA *ptr = &path->ptr[path->len - 1];
150
151         /* if we already have a (pinned) linestyle, we're done */
152         if (RNA_struct_is_a(ptr->type, &RNA_FreestyleLineStyle)) {
153                 return 1;
154         }
155         /* if we have a scene, use the lineset's linestyle */
156         else if (buttons_context_path_scene(path)) {
157                 scene = path->ptr[path->len - 1].data;
158                 linestyle = BKE_linestyle_active_from_scene(scene);
159                 if (linestyle) {
160                         RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]);
161                         path->len++;
162                         return 1;
163                 }
164         }
165
166         /* no path to a linestyle possible */
167         return 0;
168 }
169
170 static int buttons_context_path_object(ButsContextPath *path)
171 {
172         Scene *scene;
173         Object *ob;
174         PointerRNA *ptr = &path->ptr[path->len - 1];
175
176         /* if we already have a (pinned) object, we're done */
177         if (RNA_struct_is_a(ptr->type, &RNA_Object)) {
178                 return 1;
179         }
180         /* if we have a scene, use the scene's active object */
181         else if (buttons_context_path_scene(path)) {
182                 scene = path->ptr[path->len - 1].data;
183                 ob = (scene->basact) ? scene->basact->object : NULL;
184
185                 if (ob) {
186                         RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
187                         path->len++;
188
189                         return 1;
190                 }
191         }
192
193         /* no path to a object possible */
194         return 0;
195 }
196
197 static int buttons_context_path_data(ButsContextPath *path, int type)
198 {
199         Object *ob;
200         PointerRNA *ptr = &path->ptr[path->len - 1];
201
202         /* if we already have a data, we're done */
203         if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
204         else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
205         else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
206         else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
207         else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
208         else if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
209         else if (RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
210         else if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1;
211         /* try to get an object in the path, no pinning supported here */
212         else if (buttons_context_path_object(path)) {
213                 ob = path->ptr[path->len - 1].data;
214
215                 if (ob && (type == -1 || type == ob->type)) {
216                         RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
217                         path->len++;
218
219                         return 1;
220                 }
221         }
222
223         /* no path to data possible */
224         return 0;
225 }
226
227 static int buttons_context_path_modifier(ButsContextPath *path)
228 {
229         Object *ob;
230
231         if (buttons_context_path_object(path)) {
232                 ob = path->ptr[path->len - 1].data;
233
234                 if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
235                         return 1;
236         }
237
238         return 0;
239 }
240
241 static int buttons_context_path_material(ButsContextPath *path, bool for_texture, bool new_shading)
242 {
243         Object *ob;
244         PointerRNA *ptr = &path->ptr[path->len - 1];
245         Material *ma;
246
247         /* if we already have a (pinned) material, we're done */
248         if (RNA_struct_is_a(ptr->type, &RNA_Material)) {
249                 return 1;
250         }
251         /* if we have an object, use the object material slot */
252         else if (buttons_context_path_object(path)) {
253                 ob = path->ptr[path->len - 1].data;
254
255                 if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
256                         ma = give_current_material(ob, ob->actcol);
257                         RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
258                         path->len++;
259
260                         if (for_texture && give_current_material_texture_node(ma))
261                                 return 1;
262
263                         if (!new_shading) {
264                                 /* Only try to get mat from node in case of old shading system (see T40331). */
265                                 ma = give_node_material(ma);
266                                 if (ma) {
267                                         RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
268                                         path->len++;
269                                 }
270                         }
271                         return 1;
272                 }
273         }
274
275         /* no path to a material possible */
276         return 0;
277 }
278
279 static int buttons_context_path_bone(ButsContextPath *path)
280 {
281         bArmature *arm;
282         EditBone *edbo;
283
284         /* if we have an armature, get the active bone */
285         if (buttons_context_path_data(path, OB_ARMATURE)) {
286                 arm = path->ptr[path->len - 1].data;
287
288                 if (arm->edbo) {
289                         if (arm->act_edbone) {
290                                 edbo = arm->act_edbone;
291                                 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
292                                 path->len++;
293                                 return 1;
294                         }
295                 }
296                 else {
297                         if (arm->act_bone) {
298                                 RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
299                                 path->len++;
300                                 return 1;
301                         }
302                 }
303         }
304
305         /* no path to a bone possible */
306         return 0;
307 }
308
309 static int buttons_context_path_pose_bone(ButsContextPath *path)
310 {
311         PointerRNA *ptr = &path->ptr[path->len - 1];
312
313         /* if we already have a (pinned) PoseBone, we're done */
314         if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
315                 return 1;
316         }
317
318         /* if we have an armature, get the active bone */
319         if (buttons_context_path_object(path)) {
320                 Object *ob = path->ptr[path->len - 1].data;
321                 bArmature *arm = ob->data; /* path->ptr[path->len-1].data - works too */
322
323                 if (ob->type != OB_ARMATURE || arm->edbo) {
324                         return 0;
325                 }
326                 else {
327                         if (arm->act_bone) {
328                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, arm->act_bone->name);
329                                 if (pchan) {
330                                         RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
331                                         path->len++;
332                                         return 1;
333                                 }
334                         }
335                 }
336         }
337
338         /* no path to a bone possible */
339         return 0;
340 }
341
342
343 static int buttons_context_path_particle(ButsContextPath *path)
344 {
345         Object *ob;
346         ParticleSystem *psys;
347         PointerRNA *ptr = &path->ptr[path->len - 1];
348
349         /* if we already have (pinned) particle settings, we're done */
350         if (RNA_struct_is_a(ptr->type, &RNA_ParticleSettings)) {
351                 return 1;
352         }
353         /* if we have an object, get the active particle system */
354         if (buttons_context_path_object(path)) {
355                 ob = path->ptr[path->len - 1].data;
356
357                 if (ob && ob->type == OB_MESH) {
358                         psys = psys_get_current(ob);
359
360                         RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
361                         path->len++;
362                         return 1;
363                 }
364         }
365
366         /* no path to a particle system possible */
367         return 0;
368 }
369
370 static int buttons_context_path_brush(ButsContextPath *path)
371 {
372         Scene *scene;
373         Brush *br = NULL;
374         PointerRNA *ptr = &path->ptr[path->len - 1];
375
376         /* if we already have a (pinned) brush, we're done */
377         if (RNA_struct_is_a(ptr->type, &RNA_Brush)) {
378                 return 1;
379         }
380         /* if we have a scene, use the toolsettings brushes */
381         else if (buttons_context_path_scene(path)) {
382                 scene = path->ptr[path->len - 1].data;
383
384                 if (scene)
385                         br = BKE_paint_brush(BKE_paint_get_active(scene));
386
387                 if (br) {
388                         RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
389                         path->len++;
390
391                         return 1;
392                 }
393         }
394
395         /* no path to a brush possible */
396         return 0;
397 }
398
399 static int buttons_context_path_texture(ButsContextPath *path, ButsContextTexture *ct)
400 {
401         if (ct) {
402                 /* new shading system */
403                 PointerRNA *ptr = &path->ptr[path->len - 1];
404                 ID *id;
405
406                 /* if we already have a (pinned) texture, we're done */
407                 if (RNA_struct_is_a(ptr->type, &RNA_Texture))
408                         return 1;
409
410                 if (!ct->user)
411                         return 0;
412                 
413                 id = ct->user->id;
414
415                 if (id) {
416                         if (GS(id->name) == ID_BR)
417                                 buttons_context_path_brush(path);
418                         else if (GS(id->name) == ID_MA)
419                                 buttons_context_path_material(path, false, true);
420                         else if (GS(id->name) == ID_WO)
421                                 buttons_context_path_world(path);
422                         else if (GS(id->name) == ID_LA)
423                                 buttons_context_path_data(path, OB_LAMP);
424                         else if (GS(id->name) == ID_PA)
425                                 buttons_context_path_particle(path);
426                         else if (GS(id->name) == ID_OB)
427                                 buttons_context_path_object(path);
428                         else if (GS(id->name) == ID_LS)
429                                 buttons_context_path_linestyle(path);
430                 }
431
432                 if (ct->texture) {
433                         RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
434                         path->len++;
435                 }
436
437                 return 1;
438         }
439         else {
440                 /* old shading system */
441                 Material *ma;
442                 Lamp *la;
443                 World *wo;
444                 ParticleSystem *psys;
445                 FreestyleLineStyle *ls;
446                 Tex *tex;
447                 PointerRNA *ptr = &path->ptr[path->len - 1];
448
449                 /* if we already have a (pinned) texture, we're done */
450                 if (RNA_struct_is_a(ptr->type, &RNA_Texture)) {
451                         return 1;
452                 }
453                 /* try world */
454                 else if ((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
455                         wo = path->ptr[path->len - 1].data;
456
457                         if (wo && GS(wo->id.name) == ID_WO) {
458                                 tex = give_current_world_texture(wo);
459
460                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
461                                 path->len++;
462                                 return 1;
463                         }
464                 }
465                 /* try particles */
466                 else if ((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
467                         if (path->ptr[path->len - 1].type == &RNA_ParticleSettings) {
468                                 ParticleSettings *part = path->ptr[path->len - 1].data;
469
470                                 tex = give_current_particle_texture(part);
471                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
472                                 path->len++;
473                                 return 1;
474                         }
475                         else {
476                                 psys = path->ptr[path->len - 1].data;
477
478                                 if (psys && psys->part && GS(psys->part->id.name) == ID_PA) {
479                                         tex = give_current_particle_texture(psys->part);
480
481                                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
482                                         path->len++;
483                                         return 1;
484                                 }
485                         }
486                 }
487                 /* try material */
488                 else if ((path->tex_ctx == SB_TEXC_MATERIAL) && buttons_context_path_material(path, true, false)) {
489                         ma = path->ptr[path->len - 1].data;
490
491                         if (ma) {
492                                 tex = give_current_material_texture(ma);
493
494                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
495                                 path->len++;
496                                 return 1;
497                         }
498                 }
499                 /* try lamp */
500                 else if ((path->tex_ctx == SB_TEXC_LAMP) && buttons_context_path_data(path, OB_LAMP)) {
501                         la = path->ptr[path->len - 1].data;
502
503                         if (la) {
504                                 tex = give_current_lamp_texture(la);
505
506                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
507                                 path->len++;
508                                 return 1;
509                         }
510                 }
511                 /* try linestyle */
512                 else if ((path->tex_ctx == SB_TEXC_LINESTYLE) && buttons_context_path_linestyle(path)) {
513                         ls = path->ptr[path->len - 1].data;
514
515                         if (ls) {
516                                 tex = give_current_linestyle_texture(ls);
517
518                                 RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
519                                 path->len++;
520                                 return 1;
521                         }
522                 }
523         }
524
525         /* no path to a texture possible */
526         return 0;
527 }
528
529 #ifdef WITH_FREESTYLE
530 static bool buttons_context_linestyle_pinnable(const bContext *C)
531 {
532         Scene *scene = CTX_data_scene(C);
533         SceneRenderLayer *actsrl;
534         FreestyleConfig *config;
535         SpaceButs *sbuts;
536
537         /* if Freestyle is disabled in the scene */
538         if ((scene->r.mode & R_EDGE_FRS) == 0) {
539                 return false;
540         }
541         /* if Freestyle is not in the Parameter Editor mode */
542         actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
543         config = &actsrl->freestyleConfig;
544         if (config->mode != FREESTYLE_CONTROL_EDITOR_MODE) {
545                 return false;
546         }
547         /* if the scene has already been pinned */
548         sbuts = CTX_wm_space_buts(C);
549         if (sbuts->pinid && sbuts->pinid == &scene->id) {
550                 return false;
551         }
552         return true;
553 }
554 #endif
555
556 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
557 {
558         SpaceButs *sbuts = CTX_wm_space_buts(C);
559         ID *id;
560         int found;
561
562         memset(path, 0, sizeof(*path));
563         path->flag = flag;
564         path->tex_ctx = sbuts->texture_context;
565
566         /* if some ID datablock is pinned, set the root pointer */
567         if (sbuts->pinid) {
568                 id = sbuts->pinid;
569
570                 RNA_id_pointer_create(id, &path->ptr[0]);
571                 path->len++;
572         }
573
574         /* no pinned root, use scene as root */
575         if (path->len == 0) {
576                 id = (ID *)CTX_data_scene(C);
577                 RNA_id_pointer_create(id, &path->ptr[0]);
578                 path->len++;
579         }
580
581         /* now for each buttons context type, we try to construct a path,
582          * tracing back recursively */
583         switch (mainb) {
584                 case BCONTEXT_SCENE:
585                 case BCONTEXT_RENDER:
586                         found = buttons_context_path_scene(path);
587                         break;
588                 case BCONTEXT_RENDER_LAYER:
589 #ifdef WITH_FREESTYLE
590                         if (buttons_context_linestyle_pinnable(C)) {
591                                 found = buttons_context_path_linestyle(path);
592                                 if (found) {
593                                         break;
594                                 }
595                         }
596 #endif
597                         found = buttons_context_path_scene(path);
598                         break;
599                 case BCONTEXT_WORLD:
600                         found = buttons_context_path_world(path);
601                         break;
602                 case BCONTEXT_OBJECT:
603                 case BCONTEXT_PHYSICS:
604                 case BCONTEXT_CONSTRAINT:
605                         found = buttons_context_path_object(path);
606                         break;
607                 case BCONTEXT_MODIFIER:
608                         found = buttons_context_path_modifier(path);
609                         break;
610                 case BCONTEXT_DATA:
611                         found = buttons_context_path_data(path, -1);
612                         break;
613                 case BCONTEXT_PARTICLE:
614                         found = buttons_context_path_particle(path);
615                         break;
616                 case BCONTEXT_MATERIAL:
617                         found = buttons_context_path_material(path, false, (sbuts->texuser != NULL));
618                         break;
619                 case BCONTEXT_TEXTURE:
620                         found = buttons_context_path_texture(path, sbuts->texuser);
621                         break;
622                 case BCONTEXT_BONE:
623                         found = buttons_context_path_bone(path);
624                         if (!found)
625                                 found = buttons_context_path_data(path, OB_ARMATURE);
626                         break;
627                 case BCONTEXT_BONE_CONSTRAINT:
628                         found = buttons_context_path_pose_bone(path);
629                         break;
630                 default:
631                         found = 0;
632                         break;
633         }
634
635         return found;
636 }
637
638 static int buttons_shading_context(const bContext *C, int mainb)
639 {
640         Object *ob = CTX_data_active_object(C);
641
642         if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
643                 return 1;
644         if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
645                 return 1;
646         
647         return 0;
648 }
649
650 static int buttons_shading_new_context(const bContext *C, int flag)
651 {
652         Object *ob = CTX_data_active_object(C);
653
654         if (flag & (1 << BCONTEXT_MATERIAL))
655                 return BCONTEXT_MATERIAL;
656         else if (ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA)))
657                 return BCONTEXT_DATA;
658         else if (flag & (1 << BCONTEXT_WORLD))
659                 return BCONTEXT_WORLD;
660         
661         return BCONTEXT_RENDER;
662 }
663
664 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
665 {
666         ButsContextPath *path;
667         PointerRNA *ptr;
668         int a, pflag = 0, flag = 0;
669
670         if (!sbuts->path)
671                 sbuts->path = MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
672
673         path = sbuts->path;
674
675         /* We need to set Scene path now! Else, buttons_texture_context_compute() might not get a valid scene. */
676         buttons_context_path(C, path, BCONTEXT_SCENE, pflag);
677
678         buttons_texture_context_compute(C, sbuts);
679
680         /* for each context, see if we can compute a valid path to it, if
681          * this is the case, we know we have to display the button */
682         for (a = 0; a < BCONTEXT_TOT; a++) {
683                 if (buttons_context_path(C, path, a, pflag)) {
684                         flag |= (1 << a);
685
686                         /* setting icon for data context */
687                         if (a == BCONTEXT_DATA) {
688                                 ptr = &path->ptr[path->len - 1];
689
690                                 if (ptr->type)
691                                         sbuts->dataicon = RNA_struct_ui_icon(ptr->type);
692                                 else
693                                         sbuts->dataicon = ICON_EMPTY_DATA;
694                         }
695                 }
696         }
697
698         /* always try to use the tab that was explicitly
699          * set to the user, so that once that context comes
700          * back, the tab is activated again */
701         sbuts->mainb = sbuts->mainbuser;
702
703         /* in case something becomes invalid, change */
704         if ((flag & (1 << sbuts->mainb)) == 0) {
705                 if (sbuts->flag & SB_SHADING_CONTEXT) {
706                         /* try to keep showing shading related buttons */
707                         sbuts->mainb = buttons_shading_new_context(C, flag);
708                 }
709                 else if (flag & BCONTEXT_OBJECT) {
710                         sbuts->mainb = BCONTEXT_OBJECT;
711                 }
712                 else {
713                         for (a = 0; a < BCONTEXT_TOT; a++) {
714                                 if (flag & (1 << a)) {
715                                         sbuts->mainb = a;
716                                         break;
717                                 }
718                         }
719                 }
720         }
721
722         buttons_context_path(C, path, sbuts->mainb, pflag);
723
724         if (!(flag & (1 << sbuts->mainb))) {
725                 if (flag & (1 << BCONTEXT_OBJECT))
726                         sbuts->mainb = BCONTEXT_OBJECT;
727                 else
728                         sbuts->mainb = BCONTEXT_SCENE;
729         }
730
731         if (buttons_shading_context(C, sbuts->mainb))
732                 sbuts->flag |= SB_SHADING_CONTEXT;
733         else
734                 sbuts->flag &= ~SB_SHADING_CONTEXT;
735
736         sbuts->pathflag = flag;
737 }
738
739 /************************* Context Callback ************************/
740
741 const char *buttons_context_dir[] = {
742         "texture_slot", "scene", "world", "object", "mesh", "armature", "lattice", "curve",
743         "meta_ball", "lamp", "speaker", "camera", "material", "material_slot",
744         "texture", "texture_user", "texture_user_property", "bone", "edit_bone",
745         "pose_bone", "particle_system", "particle_system_editable", "particle_settings",
746         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint",
747         "line_style", NULL
748 };
749
750 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
751 {
752         SpaceButs *sbuts = CTX_wm_space_buts(C);
753         ButsContextPath *path = sbuts ? sbuts->path : NULL;
754
755         if (!path)
756                 return 0;
757
758         /* here we handle context, getting data from precomputed path */
759         if (CTX_data_dir(member)) {
760                 /* in case of new shading system we skip texture_slot, complex python
761                  * UI script logic depends on checking if this is available */
762                 if (sbuts->texuser)
763                         CTX_data_dir_set(result, buttons_context_dir + 1);
764                 else
765                         CTX_data_dir_set(result, buttons_context_dir);
766                 return 1;
767         }
768         else if (CTX_data_equals(member, "scene")) {
769                 /* Do not return one here if scene not found in path, in this case we want to get default context scene! */
770                 return set_pointer_type(path, result, &RNA_Scene);
771         }
772         else if (CTX_data_equals(member, "world")) {
773                 set_pointer_type(path, result, &RNA_World);
774                 return 1;
775         }
776         else if (CTX_data_equals(member, "object")) {
777                 set_pointer_type(path, result, &RNA_Object);
778                 return 1;
779         }
780         else if (CTX_data_equals(member, "mesh")) {
781                 set_pointer_type(path, result, &RNA_Mesh);
782                 return 1;
783         }
784         else if (CTX_data_equals(member, "armature")) {
785                 set_pointer_type(path, result, &RNA_Armature);
786                 return 1;
787         }
788         else if (CTX_data_equals(member, "lattice")) {
789                 set_pointer_type(path, result, &RNA_Lattice);
790                 return 1;
791         }
792         else if (CTX_data_equals(member, "curve")) {
793                 set_pointer_type(path, result, &RNA_Curve);
794                 return 1;
795         }
796         else if (CTX_data_equals(member, "meta_ball")) {
797                 set_pointer_type(path, result, &RNA_MetaBall);
798                 return 1;
799         }
800         else if (CTX_data_equals(member, "lamp")) {
801                 set_pointer_type(path, result, &RNA_Lamp);
802                 return 1;
803         }
804         else if (CTX_data_equals(member, "camera")) {
805                 set_pointer_type(path, result, &RNA_Camera);
806                 return 1;
807         }
808         else if (CTX_data_equals(member, "speaker")) {
809                 set_pointer_type(path, result, &RNA_Speaker);
810                 return 1;
811         }
812         else if (CTX_data_equals(member, "material")) {
813                 set_pointer_type(path, result, &RNA_Material);
814                 return 1;
815         }
816         else if (CTX_data_equals(member, "texture")) {
817                 ButsContextTexture *ct = sbuts->texuser;
818
819                 if (ct) {
820                         /* new shading system */
821                         CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
822                 }
823                 else {
824                         /* old shading system */
825                         set_pointer_type(path, result, &RNA_Texture);
826                 }
827
828                 return 1;
829         }
830         else if (CTX_data_equals(member, "material_slot")) {
831                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
832
833                 if (ptr) {
834                         Object *ob = ptr->data;
835
836                         if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) {
837                                 /* a valid actcol isn't ensured [#27526] */
838                                 int matnr = ob->actcol - 1;
839                                 if (matnr < 0) matnr = 0;
840                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]);
841                         }
842                 }
843
844                 return 1;
845         }
846         else if (CTX_data_equals(member, "texture_user")) {
847                 ButsContextTexture *ct = sbuts->texuser;
848
849                 if (!ct)
850                         return -1;  /* old shading system (found but not available) */
851
852                 if (ct->user && ct->user->ptr.data) {
853                         ButsTextureUser *user = ct->user;
854                         CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data);
855                 }
856
857                 return 1;
858         }
859         else if (CTX_data_equals(member, "texture_user_property")) {
860                 ButsContextTexture *ct = sbuts->texuser;
861
862                 if (!ct)
863                         return -1;  /* old shading system (found but not available) */
864
865                 if (ct->user && ct->user->ptr.data) {
866                         ButsTextureUser *user = ct->user;
867                         CTX_data_pointer_set(result, NULL, &RNA_Property, user->prop);
868                 }
869
870                 return 1;
871         }
872         else if (CTX_data_equals(member, "texture_node")) {
873                 ButsContextTexture *ct = sbuts->texuser;
874
875                 if (ct) {
876                         /* new shading system */
877                         if (ct->user && ct->user->node) {
878                                 CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node);
879                         }
880
881                         return 1;
882                 }
883                 else {
884                         /* old shading system */
885                         PointerRNA *ptr;
886
887                         if ((ptr = get_pointer_type(path, &RNA_Material))) {
888                                 Material *ma = ptr->data;
889
890                                 if (ma) {
891                                         bNode *node = give_current_material_texture_node(ma);
892                                         CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node);
893                                 }
894                         }
895
896                         return 1;
897                 }
898         }
899         else if (CTX_data_equals(member, "texture_slot")) {
900                 ButsContextTexture *ct = sbuts->texuser;
901                 PointerRNA *ptr;
902
903                 /* Particles slots are used in both old and new textures handling. */
904                 if ((ptr = get_pointer_type(path, &RNA_ParticleSystem))) {
905                         ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;
906
907                         if (part)
908                                 CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
909                 }
910                 else if (ct) {
911                         return 0;  /* new shading system */
912                 }
913                 else if ((ptr = get_pointer_type(path, &RNA_Material))) {
914                         Material *ma = ptr->data;
915
916                         /* if we have a node material, get slot from material in material node */
917                         if (ma && ma->use_nodes && ma->nodetree) {
918                                 /* if there's an active texture node in the node tree,
919                                  * then that texture is in context directly, without a texture slot */
920                                 if (give_current_material_texture_node(ma))
921                                         return 0;
922
923                                 ma = give_node_material(ma);
924                                 if (ma)
925                                         CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
926                                 else
927                                         return 0;
928                         }
929                         else if (ma) {
930                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
931                         }
932                 }
933                 else if ((ptr = get_pointer_type(path, &RNA_Lamp))) {
934                         Lamp *la = ptr->data;
935
936                         if (la)
937                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
938                 }
939                 else if ((ptr = get_pointer_type(path, &RNA_World))) {
940                         World *wo = ptr->data;
941
942                         if (wo)
943                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
944                 }
945                 else if ((ptr = get_pointer_type(path, &RNA_FreestyleLineStyle))) {
946                         FreestyleLineStyle *ls = ptr->data;
947
948                         if (ls)
949                                 CTX_data_pointer_set(result, &ls->id, &RNA_LineStyleTextureSlot, ls->mtex[(int)ls->texact]);
950                 }
951
952                 return 1;
953         }
954         else if (CTX_data_equals(member, "bone")) {
955                 set_pointer_type(path, result, &RNA_Bone);
956                 return 1;
957         }
958         else if (CTX_data_equals(member, "edit_bone")) {
959                 set_pointer_type(path, result, &RNA_EditBone);
960                 return 1;
961         }
962         else if (CTX_data_equals(member, "pose_bone")) {
963                 set_pointer_type(path, result, &RNA_PoseBone);
964                 return 1;
965         }
966         else if (CTX_data_equals(member, "particle_system")) {
967                 set_pointer_type(path, result, &RNA_ParticleSystem);
968                 return 1;
969         }
970         else if (CTX_data_equals(member, "particle_system_editable")) {
971                 if (PE_poll((bContext *)C))
972                         set_pointer_type(path, result, &RNA_ParticleSystem);
973                 else
974                         CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
975                 return 1;
976         }
977         else if (CTX_data_equals(member, "particle_settings")) {
978                 /* only available when pinned */
979                 PointerRNA *ptr = get_pointer_type(path, &RNA_ParticleSettings);
980                 
981                 if (ptr && ptr->data) {
982                         CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, ptr->data);
983                         return 1;
984                 }
985                 else {
986                         /* get settings from active particle system instead */
987                         ptr = get_pointer_type(path, &RNA_ParticleSystem);
988                         
989                         if (ptr && ptr->data) {
990                                 ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;
991                                 CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, part);
992                                 return 1;
993                         }
994                 }
995                 set_pointer_type(path, result, &RNA_ParticleSettings);
996                 return 1;
997         }
998         else if (CTX_data_equals(member, "cloth")) {
999                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1000
1001                 if (ptr && ptr->data) {
1002                         Object *ob = ptr->data;
1003                         ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
1004                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
1005                         return 1;
1006                 }
1007         }
1008         else if (CTX_data_equals(member, "soft_body")) {
1009                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1010
1011                 if (ptr && ptr->data) {
1012                         Object *ob = ptr->data;
1013                         ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
1014                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
1015                         return 1;
1016                 }
1017         }
1018         else if (CTX_data_equals(member, "fluid")) {
1019                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1020
1021                 if (ptr && ptr->data) {
1022                         Object *ob = ptr->data;
1023                         ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
1024                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
1025                         return 1;
1026                 }
1027         }
1028         
1029         else if (CTX_data_equals(member, "smoke")) {
1030                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1031
1032                 if (ptr && ptr->data) {
1033                         Object *ob = ptr->data;
1034                         ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
1035                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
1036                         return 1;
1037                 }
1038         }
1039         else if (CTX_data_equals(member, "collision")) {
1040                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1041
1042                 if (ptr && ptr->data) {
1043                         Object *ob = ptr->data;
1044                         ModifierData *md = modifiers_findByType(ob, eModifierType_Collision);
1045                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
1046                         return 1;
1047                 }
1048         }
1049         else if (CTX_data_equals(member, "brush")) {
1050                 set_pointer_type(path, result, &RNA_Brush);
1051                 return 1;
1052         }
1053         else if (CTX_data_equals(member, "dynamic_paint")) {
1054                 PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
1055
1056                 if (ptr && ptr->data) {
1057                         Object *ob = ptr->data;
1058                         ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint);
1059                         CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
1060                         return 1;
1061                 }
1062         }
1063         else if (CTX_data_equals(member, "line_style")) {
1064                 set_pointer_type(path, result, &RNA_FreestyleLineStyle);
1065                 return 1;
1066         }
1067         else {
1068                 return 0; /* not found */
1069         }
1070
1071         return -1; /* found but not available */
1072 }
1073
1074 /************************* Drawing the Path ************************/
1075
1076 static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1077 {
1078         SpaceButs *sbuts = CTX_wm_space_buts(C);
1079
1080         if (sbuts->flag & SB_PIN_CONTEXT) {
1081                 sbuts->pinid = buttons_context_id_path(C);
1082         }
1083         else
1084                 sbuts->pinid = NULL;
1085         
1086         ED_area_tag_redraw(CTX_wm_area(C));
1087 }
1088
1089 void buttons_context_draw(const bContext *C, uiLayout *layout)
1090 {
1091         SpaceButs *sbuts = CTX_wm_space_buts(C);
1092         ButsContextPath *path = sbuts->path;
1093         uiLayout *row;
1094         uiBlock *block;
1095         uiBut *but;
1096         PointerRNA *ptr;
1097         char namebuf[128], *name;
1098         int a, icon;
1099
1100         if (!path)
1101                 return;
1102
1103         row = uiLayoutRow(layout, true);
1104         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
1105
1106         block = uiLayoutGetBlock(row);
1107         UI_block_emboss_set(block, UI_EMBOSS_NONE);
1108         but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
1109                                0, 0, 0, 0, TIP_("Follow context or keep fixed data-block displayed"));
1110         UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
1111         UI_but_func_set(but, pin_cb, NULL, NULL);
1112
1113         for (a = 0; a < path->len; a++) {
1114                 ptr = &path->ptr[a];
1115
1116                 if (a != 0)
1117                         uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
1118
1119                 if (ptr->data) {
1120                         icon = RNA_struct_ui_icon(ptr->type);
1121                         name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
1122
1123                         if (name) {
1124                                 if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
1125                                         uiItemLDrag(row, ptr, "", icon);  /* save some space */
1126                                 else
1127                                         uiItemLDrag(row, ptr, name, icon);
1128
1129                                 if (name != namebuf)
1130                                         MEM_freeN(name);
1131                         }
1132                         else
1133                                 uiItemL(row, "", icon);
1134                 }
1135         }
1136 }
1137
1138 static void buttons_panel_context(const bContext *C, Panel *pa)
1139 {
1140         buttons_context_draw(C, pa->layout);
1141 }
1142
1143 void buttons_context_register(ARegionType *art)
1144 {
1145         PanelType *pt;
1146
1147         pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
1148         strcpy(pt->idname, "BUTTONS_PT_context");
1149         strcpy(pt->label, N_("Context"));  /* XXX C panels are not available through RNA (bpy.types)! */
1150         strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1151         pt->draw = buttons_panel_context;
1152         pt->flag = PNL_NO_HEADER;
1153         BLI_addtail(&art->paneltypes, pt);
1154 }
1155
1156 ID *buttons_context_id_path(const bContext *C)
1157 {
1158         SpaceButs *sbuts = CTX_wm_space_buts(C);
1159         ButsContextPath *path = sbuts->path;
1160         PointerRNA *ptr;
1161         int a;
1162
1163         if (path->len) {
1164                 for (a = path->len - 1; a >= 0; a--) {
1165                         ptr = &path->ptr[a];
1166
1167                         /* pin particle settings instead of system, since only settings are an idblock*/
1168                         if (sbuts->mainb == BCONTEXT_PARTICLE && sbuts->flag & SB_PIN_CONTEXT) {
1169                                 if (ptr->type == &RNA_ParticleSystem && ptr->data) {
1170                                         ParticleSystem *psys = (ParticleSystem *)ptr->data;
1171                                         return &psys->part->id;
1172                                 }
1173                         }
1174
1175                         if (ptr->id.data) {
1176                                 return ptr->id.data;
1177                         }
1178                 }
1179         }
1180
1181         return NULL;
1182 }