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