Merged changes from trunk r58324-58419.
[blender.git] / source / blender / editors / space_outliner / outliner_draw.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) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_outliner/outliner_draw.c
29  *  \ingroup spoutliner
30  */
31
32 #include "DNA_armature_types.h"
33 #include "DNA_group_types.h"
34 #include "DNA_lamp_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_sequence_types.h"
38
39 #include "BLI_math.h"
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
42 #include "BLI_ghash.h"
43
44 #include "BLF_translation.h"
45
46 #include "BKE_context.h"
47 #include "BKE_deform.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_global.h"
50 #include "BKE_library.h"
51 #include "BKE_main.h"
52 #include "BKE_modifier.h"
53 #include "BKE_report.h"
54 #include "BKE_scene.h"
55 #include "BKE_object.h"
56
57 #include "ED_armature.h"
58 #include "ED_object.h"
59 #include "ED_screen.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "BIF_gl.h"
65 #include "BIF_glutil.h"
66
67 #include "UI_interface.h"
68 #include "UI_interface_icons.h"
69 #include "UI_resources.h"
70 #include "UI_view2d.h"
71
72 #include "RNA_access.h"
73
74 #include "outliner_intern.h"
75
76 /* disable - this is far too slow - campbell */
77 // #define USE_GROUP_SELECT
78
79 /* ****************************************************** */
80 /* Tree Size Functions */
81
82 static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
83 {
84         TreeElement *te = lb->first;
85         while (te) {
86                 TreeStoreElem *tselem = TREESTORE(te);
87                 if (TSELEM_OPEN(tselem, soops))
88                         outliner_height(soops, &te->subtree, h);
89                 (*h) += UI_UNIT_Y;
90                 te = te->next;
91         }
92 }
93
94 #if 0  // XXX this is currently disabled until te->xend is set correctly
95 static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
96 {
97         TreeElement *te = lb->first;
98         while (te) {
99 //              TreeStoreElem *tselem = TREESTORE(te);
100                 
101                 // XXX fixme... te->xend is not set yet
102                 if (!TSELEM_OPEN(tselem, soops)) {
103                         if (te->xend > *w)
104                                 *w = te->xend;
105                 }
106                 outliner_width(soops, &te->subtree, w);
107                 te = te->next;
108         }
109 }
110 #endif
111
112 static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int startx)
113 {
114         TreeElement *te = lb->first;
115         while (te) {
116                 TreeStoreElem *tselem = TREESTORE(te);
117                 // XXX fixme... (currently, we're using a fixed length of 100)!
118 #if 0
119                 if (te->xend) {
120                         if (te->xend > *w)
121                                 *w = te->xend;
122                 }
123 #endif
124                 if (startx + 100 > *w)
125                         *w = startx + 100;
126
127                 if (TSELEM_OPEN(tselem, soops))
128                         outliner_rna_width(soops, &te->subtree, w, startx + UI_UNIT_X);
129                 te = te->next;
130         }
131 }
132
133 /* ****************************************************** */
134
135 static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag)
136 {
137         Object *obedit = CTX_data_edit_object(C);
138         bArmature *arm = obedit->data;
139         EditBone *ebone;
140         
141         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
142                 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
143                         if (set_flag) {
144                                 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
145                                 ebone->flag |= flag;
146                         }
147                         else {
148                                 ebone->flag &= ~flag;
149                         }
150                 }
151         }
152 }
153
154 static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bone_parent, int flag, bool set_flag)
155 {
156         Bone *bone;
157         for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
158                 if (set_flag) {
159                         bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
160                         bone->flag |= flag;
161                 }
162                 else {
163                         bone->flag &= ~flag;
164                 }
165                 restrictbutton_recursive_bone(C, arm, bone, flag, set_flag);
166         }
167
168 }
169
170 static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
171                                            bool state, bool deselect)
172 {
173         Main *bmain = CTX_data_main(C);
174         Object *ob;
175         for (ob = bmain->object.first; ob; ob = ob->id.next) {
176                 if (BKE_object_is_child_recursive(ob_parent, ob)) {
177                         if (state) {
178                                 ob->restrictflag |= flag;
179                                 if (deselect) {
180                                         ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
181                                 }
182                         }
183                         else {
184                                 ob->restrictflag &= ~flag;
185                         }
186                 }
187         }
188 }
189
190 static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
191 {
192         Scene *scene = (Scene *)poin;
193         Object *ob = (Object *)poin2;
194         
195         if (!common_restrict_check(C, ob)) return;
196         
197         /* deselect objects that are invisible */
198         if (ob->restrictflag & OB_RESTRICT_VIEW) {
199                 /* Ouch! There is no backwards pointer from Object to Base, 
200                  * so have to do loop to find it. */
201                 ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
202         }
203
204         if (CTX_wm_window(C)->eventstate->ctrl) {
205                 restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
206                                                (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true);
207         }
208
209         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
210
211 }
212
213 static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
214 {
215         Scene *scene = (Scene *)poin;
216         Object *ob = (Object *)poin2;
217         
218         if (!common_restrict_check(C, ob)) return;
219         
220         /* if select restriction has just been turned on */
221         if (ob->restrictflag & OB_RESTRICT_SELECT) {
222                 /* Ouch! There is no backwards pointer from Object to Base, 
223                  * so have to do loop to find it. */
224                 ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
225         }
226
227         if (CTX_wm_window(C)->eventstate->ctrl) {
228                 restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
229                                                (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true);
230         }
231
232         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
233
234 }
235
236 static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
237 {
238         Object *ob = (Object *)poin2;
239
240         if (CTX_wm_window(C)->eventstate->ctrl) {
241                 restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
242                                                (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false);
243         }
244
245         WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
246 }
247
248 static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2))
249 {
250         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
251 }
252
253 static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *poin2)
254 {
255         Object *ob = (Object *)poin2;
256         
257         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
258
259         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
260 }
261
262 static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
263 {
264         bArmature *arm = (bArmature *)poin;
265         Bone *bone = (Bone *)poin2;
266         if (bone && (bone->flag & BONE_HIDDEN_P))
267                 bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
268
269         if (CTX_wm_window(C)->eventstate->ctrl) {
270                 restrictbutton_recursive_bone(C, arm, bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
271         }
272
273         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
274 }
275
276 static void restrictbutton_bone_select_cb(bContext *C, void *poin, void *poin2)
277 {
278         bArmature *arm = (bArmature *)poin;
279         Bone *bone = (Bone *)poin2;
280         if (bone && (bone->flag & BONE_UNSELECTABLE))
281                 bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
282
283         if (CTX_wm_window(C)->eventstate->ctrl) {
284                 restrictbutton_recursive_bone(C, arm, bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
285         }
286
287         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
288 }
289
290 static void restrictbutton_ebone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
291 {
292         EditBone *ebone = (EditBone *)poin2;
293
294         if (ebone->flag & BONE_UNSELECTABLE) {
295                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
296         }
297
298         if (CTX_wm_window(C)->eventstate->ctrl) {
299                 restrictbutton_recursive_ebone(C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
300         }
301
302         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
303 }
304
305 static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
306 {
307         EditBone *ebone = (EditBone *)poin2;
308         if (ebone->flag & BONE_HIDDEN_A) {
309                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
310         }
311
312         if (CTX_wm_window(C)->eventstate->ctrl) {
313                 restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
314         }
315
316         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
317 }
318
319 static int group_restrict_flag(Group *gr, int flag)
320 {
321         GroupObject *gob;
322
323 #ifdef USE_GROUP_SELECT
324         for (gob = gr->gobject.first; gob; gob = gob->next) {
325                 if ((gob->ob->restrictflag & flag) == 0)
326                         return 0;
327         }
328         return 1;
329 #else
330         /* weak but fast */
331         if ((gob = gr->gobject.first))
332                 if ((gob->ob->restrictflag & flag) == 0)
333                         return 0;
334         return 1;
335 #endif
336 }
337
338 static int group_select_flag(Group *gr)
339 {
340         GroupObject *gob;
341
342 #ifdef USE_GROUP_SELECT
343         for (gob = gr->gobject.first; gob; gob = gob->next)
344                 if ((gob->ob->flag & SELECT))
345                         return 1;
346
347         return 0;
348 #else
349         /* weak but fast */
350         if ((gob = gr->gobject.first))
351                 if (gob->ob->flag & SELECT)
352                         return 1;
353         return 0;
354 #endif
355 }
356
357 void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
358 {
359         Scene *scene = (Scene *)poin;
360         GroupObject *gob;
361         Group *gr = (Group *)poin2;
362
363         if (group_restrict_flag(gr, flag)) {
364                 for (gob = gr->gobject.first; gob; gob = gob->next) {
365                         gob->ob->restrictflag &= ~flag;
366                         
367                         if (flag == OB_RESTRICT_VIEW)
368                                 if (gob->ob->flag & SELECT)
369                                         ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT);
370                 }
371         }
372         else {
373                 for (gob = gr->gobject.first; gob; gob = gob->next) {
374                         /* not in editmode */
375                         if (scene->obedit != gob->ob) {
376                                 gob->ob->restrictflag |= flag;
377
378                                 if (ELEM(flag, OB_RESTRICT_SELECT, OB_RESTRICT_VIEW)) {
379                                         if ((gob->ob->flag & SELECT)) {
380                                                 ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT);
381                                         }
382                                 }
383                         }
384                 }
385         }
386
387
388 static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2)
389 {
390         restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_VIEW);
391         WM_event_add_notifier(C, NC_GROUP, NULL);
392 }
393 static void restrictbutton_gr_restrict_select(bContext *C, void *poin, void *poin2)
394 {
395         restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_SELECT);
396         WM_event_add_notifier(C, NC_GROUP, NULL);
397 }
398 static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poin2)
399 {
400         restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_RENDER);
401         WM_event_add_notifier(C, NC_GROUP, NULL);
402 }
403
404
405 static void namebutton_cb(bContext *C, void *tsep, char *oldname)
406 {
407         SpaceOops *soops = CTX_wm_space_outliner(C);
408         Scene *scene = CTX_data_scene(C);
409         Object *obedit = CTX_data_edit_object(C);
410         TreeStore *ts = soops->treestore;
411         TreeStoreElem *tselem = tsep;
412         
413         if (ts && tselem) {
414                 TreeElement *te = outliner_find_tse(soops, tselem);
415                 
416                 if (tselem->type == 0) {
417                         test_idbutton(tselem->id->name);  // library.c, unique name and alpha sort
418                         
419                         switch (GS(tselem->id->name)) {
420                                 case ID_MA:
421                                         WM_event_add_notifier(C, NC_MATERIAL, NULL); break;
422                                 case ID_TE:
423                                         WM_event_add_notifier(C, NC_TEXTURE, NULL); break;
424                                 case ID_IM:
425                                         WM_event_add_notifier(C, NC_IMAGE, NULL); break;
426                                 case ID_SCE:
427                                         WM_event_add_notifier(C, NC_SCENE, NULL); break;
428                                 default:
429                                         WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break;
430                         }
431                         /* Check the library target exists */
432                         if (te->idcode == ID_LI) {
433                                 Library *lib = (Library *)tselem->id;
434                                 char expanded[FILE_MAX];
435
436                                 BKE_library_filepath_set(lib, lib->name);
437
438                                 BLI_strncpy(expanded, lib->name, sizeof(expanded));
439                                 BLI_path_abs(expanded, G.main->name);
440                                 if (!BLI_exists(expanded)) {
441                                         BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
442                                                     "Library path '%s' does not exist, correct this before saving", expanded);
443                                 }
444                         }
445                 }
446                 else {
447                         switch (tselem->type) {
448                                 case TSE_DEFGROUP:
449                                         defgroup_unique_name(te->directdata, (Object *)tselem->id); //  id = object
450                                         break;
451                                 case TSE_NLA_ACTION:
452                                         test_idbutton(tselem->id->name);
453                                         break;
454                                 case TSE_EBONE:
455                                 {
456                                         bArmature *arm = (bArmature *)tselem->id;
457                                         if (arm->edbo) {
458                                                 EditBone *ebone = te->directdata;
459                                                 char newname[sizeof(ebone->name)];
460
461                                                 /* restore bone name */
462                                                 BLI_strncpy(newname, ebone->name, sizeof(ebone->name));
463                                                 BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
464                                                 ED_armature_bone_rename(obedit->data, oldname, newname);
465                                                 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT);
466                                         }
467                                         break;
468                                 }
469
470                                 case TSE_BONE:
471                                 {
472                                         Bone *bone = te->directdata;
473                                         Object *ob;
474                                         char newname[sizeof(bone->name)];
475                                         
476                                         // always make current object active
477                                         tree_element_active(C, scene, soops, te, 1); // was set_active_object()
478                                         ob = OBACT;
479                                         
480                                         /* restore bone name */
481                                         BLI_strncpy(newname, bone->name, sizeof(bone->name));
482                                         BLI_strncpy(bone->name, oldname, sizeof(bone->name));
483                                         ED_armature_bone_rename(ob->data, oldname, newname);
484                                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
485                                         break;
486                                 }
487                                 case TSE_POSE_CHANNEL:
488                                 {
489                                         bPoseChannel *pchan = te->directdata;
490                                         Object *ob;
491                                         char newname[sizeof(pchan->name)];
492                                         
493                                         // always make current object active
494                                         tree_element_active(C, scene, soops, te, 1); // was set_active_object()
495                                         ob = OBACT;
496                                         
497                                         /* restore bone name */
498                                         BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
499                                         BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
500                                         ED_armature_bone_rename(ob->data, oldname, newname);
501                                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
502                                         break;
503                                 }
504                                 case TSE_POSEGRP:
505                                 {
506                                         Object *ob = (Object *)tselem->id; // id = object
507                                         bActionGroup *grp = te->directdata;
508                                         
509                                         BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLF_I18NCONTEXT_ID_ACTION, "Group"), '.',
510                                                        offsetof(bActionGroup, name), sizeof(grp->name));
511                                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
512                                         break;
513                                 }
514                                 case TSE_R_LAYER:
515                                         break;
516                         }
517                 }
518                 tselem->flag &= ~TSE_TEXTBUT;
519         }
520 }
521
522 static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, ListBase *lb)
523 {       
524         uiBut *bt;
525         TreeElement *te;
526         TreeStoreElem *tselem;
527         Object *ob = NULL;
528         Group  *gr = NULL;
529
530         for (te = lb->first; te; te = te->next) {
531                 tselem = TREESTORE(te);
532                 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
533                         /* objects have toggle-able restriction flags */
534                         if (tselem->type == 0 && te->idcode == ID_OB) {
535                                 PointerRNA ptr;
536                                 
537                                 ob = (Object *)tselem->id;
538                                 RNA_pointer_create((ID *)ob, &RNA_Object, ob, &ptr);
539                                 
540                                 uiBlockSetEmboss(block, UI_EMBOSSN);
541                                 bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF,
542                                                    (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
543                                                    &ptr, "hide", -1, 0, 0, -1, -1,
544                                                    TIP_("Restrict viewport visibility (Ctrl - Recursive)"));
545                                 uiButSetFunc(bt, restrictbutton_view_cb, scene, ob);
546                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
547                                 
548                                 bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF,
549                                                    (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
550                                                    &ptr, "hide_select", -1, 0, 0, -1, -1,
551                                                    TIP_("Restrict viewport selection (Ctrl - Recursive)"));
552                                 uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob);
553                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
554                                 
555                                 bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF,
556                                                    (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
557                                                    &ptr, "hide_render", -1, 0, 0, -1, -1,
558                                                    TIP_("Restrict rendering (Ctrl - Recursive)"));
559                                 uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob);
560                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
561                                 
562                                 uiBlockSetEmboss(block, UI_EMBOSS);
563                                 
564                         }
565                         if (tselem->type == 0 && te->idcode == ID_GR) {
566                                 int restrict_bool;
567                                 gr = (Group *)tselem->id;
568                                 
569                                 uiBlockSetEmboss(block, UI_EMBOSSN);
570
571                                 restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
572                                 bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
573                                                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
574                                                   NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View"));
575                                 uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr);
576                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
577
578                                 restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
579                                 bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
580                                                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
581                                                   NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View"));
582                                 uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr);
583                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
584
585                                 restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
586                                 bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
587                                                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
588                                                   NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
589                                 uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr);
590                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
591
592                                 uiBlockSetEmboss(block, UI_EMBOSS);
593                         }
594                         /* scene render layers and passes have toggle-able flags too! */
595                         else if (tselem->type == TSE_R_LAYER) {
596                                 uiBlockSetEmboss(block, UI_EMBOSSN);
597                                 
598                                 bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
599                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
600                                                       UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
601                                 uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
602                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
603                                 
604                                 uiBlockSetEmboss(block, UI_EMBOSS);
605                         }
606                         else if (tselem->type == TSE_R_PASS) {
607                                 int *layflag = te->directdata;
608                                 int passflag = 1 << tselem->nr;
609                                 
610                                 uiBlockSetEmboss(block, UI_EMBOSSN);
611                                 
612                                 
613                                 bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1,
614                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
615                                                       UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
616                                 uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
617                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
618                                 
619                                 layflag++;  /* is lay_xor */
620                                 if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
621                                           SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
622                                 {
623                                         bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
624                                                               (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
625                                                               UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
626                                         uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
627                                         uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
628                                 }
629                                 
630                                 uiBlockSetEmboss(block, UI_EMBOSS);
631                         }
632                         else if (tselem->type == TSE_MODIFIER) {
633                                 ModifierData *md = (ModifierData *)te->directdata;
634                                 ob = (Object *)tselem->id;
635                                 
636                                 uiBlockSetEmboss(block, UI_EMBOSSN);
637                                 bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
638                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
639                                                       UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
640                                                       TIP_("Restrict/Allow visibility in the 3D View"));
641                                 uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
642                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
643                                 
644                                 bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
645                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X,
646                                                       UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
647                                 uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
648                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
649
650                                 uiBlockSetEmboss(block, UI_EMBOSS);
651                         }
652                         else if (tselem->type == TSE_POSE_CHANNEL) {
653                                 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
654                                 Bone *bone = pchan->bone;
655                                 ob = (Object *)tselem->id;
656                                 
657                                 uiBlockSetEmboss(block, UI_EMBOSSN);
658                                 bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
659                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
660                                                       UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
661                                                       TIP_("Restrict/Allow visibility in the 3D View"));
662                                 uiButSetFunc(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
663                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
664                                 
665                                 bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
666                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
667                                                       UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
668                                                       TIP_("Restrict/Allow selection in the 3D View"));
669                                 uiButSetFunc(bt, restrictbutton_bone_select_cb, ob->data, bone);
670                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
671
672                                 uiBlockSetEmboss(block, UI_EMBOSS);
673                         }
674                         else if (tselem->type == TSE_EBONE) {
675                                 EditBone *ebone = (EditBone *)te->directdata;
676                                 
677                                 uiBlockSetEmboss(block, UI_EMBOSSN);
678                                 bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
679                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
680                                                       UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
681                                                       TIP_("Restrict/Allow visibility in the 3D View"));
682                                 uiButSetFunc(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
683                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
684                                 
685                                 bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
686                                                       (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
687                                                       UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
688                                                       TIP_("Restrict/Allow selection in the 3D View"));
689                                 uiButSetFunc(bt, restrictbutton_ebone_select_cb, NULL, ebone);
690                                 uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
691
692                                 uiBlockSetEmboss(block, UI_EMBOSS);
693                         }
694                 }
695                 
696                 if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
697         }
698 }
699
700 static void outliner_draw_rnacols(ARegion *ar, int sizex)
701 {
702         View2D *v2d = &ar->v2d;
703
704         float miny = v2d->cur.ymin;
705         if (miny < v2d->tot.ymin) miny = v2d->tot.ymin;
706
707         UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
708
709         /* draw column separator lines */
710         fdrawline((float)sizex,
711                   v2d->cur.ymax,
712                   (float)sizex,
713                   miny);
714
715         fdrawline((float)sizex + OL_RNA_COL_SIZEX,
716                   v2d->cur.ymax,
717                   (float)sizex + OL_RNA_COL_SIZEX,
718                   miny);
719 }
720
721 static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
722 {
723         TreeElement *te;
724         TreeStoreElem *tselem;
725         PointerRNA *ptr;
726         PropertyRNA *prop;
727         
728         uiBlockSetEmboss(block, UI_EMBOSST);
729
730         for (te = lb->first; te; te = te->next) {
731                 tselem = TREESTORE(te);
732                 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
733                         if (tselem->type == TSE_RNA_PROPERTY) {
734                                 ptr = &te->rnaptr;
735                                 prop = te->directdata;
736                                 
737                                 if (!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem, soops)))) {
738                                         uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX,
739                                                       UI_UNIT_Y - 1);
740                                 }
741                         }
742                         else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
743                                 ptr = &te->rnaptr;
744                                 prop = te->directdata;
745                                 
746                                 uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX,
747                                               UI_UNIT_Y - 1);
748                         }
749                 }
750                 
751                 if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
752         }
753
754         uiBlockSetEmboss(block, UI_EMBOSS);
755 }
756
757 static void operator_call_cb(struct bContext *UNUSED(C), void *arg_kmi, void *arg2)
758 {
759         wmOperatorType *ot = arg2;
760         wmKeyMapItem *kmi = arg_kmi;
761         
762         if (ot)
763                 BLI_strncpy(kmi->idname, ot->idname, OP_MAX_TYPENAME);
764 }
765
766 static void operator_search_cb(const struct bContext *UNUSED(C), void *UNUSED(arg_kmi),
767                                const char *str, uiSearchItems *items)
768 {
769         GHashIterator *iter = WM_operatortype_iter();
770
771         for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
772                 wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
773                 
774                 if (BLI_strcasestr(ot->idname, str)) {
775                         char name[OP_MAX_TYPENAME];
776                         
777                         /* display name for menu */
778                         WM_operator_py_idname(name, ot->idname);
779                         
780                         if (false == uiSearchItemAdd(items, name, ot, 0))
781                                 break;
782                 }
783         }
784         BLI_ghashIterator_free(iter);
785 }
786
787 /* operator Search browse menu, open */
788 static uiBlock *operator_search_menu(bContext *C, ARegion *ar, void *arg_kmi)
789 {
790         static char search[OP_MAX_TYPENAME];
791         wmEvent event;
792         wmWindow *win = CTX_wm_window(C);
793         wmKeyMapItem *kmi = arg_kmi;
794         wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
795         uiBlock *block;
796         uiBut *but;
797         
798         /* clear initial search string, then all items show */
799         search[0] = 0;
800         
801         block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
802         uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_SEARCH_MENU);
803         
804         /* fake button, it holds space for search items */
805         uiDefBut(block, LABEL, 0, "", 10, 15, uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
806         
807         but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, UI_UNIT_Y, 0, 0, "");
808         uiButSetSearchFunc(but, operator_search_cb, arg_kmi, operator_call_cb, ot);
809         
810         uiBoundsBlock(block, 6);
811         uiBlockSetDirection(block, UI_DOWN);
812         uiEndBlock(C, block);
813         
814         event = *(win->eventstate);  /* XXX huh huh? make api call */
815         event.type = EVT_BUT_OPEN;
816         event.val = KM_PRESS;
817         event.customdata = but;
818         event.customdatafree = FALSE;
819         wm_event_add(win, &event);
820         
821         return block;
822 }
823
824 #define OL_KM_KEYBOARD      0
825 #define OL_KM_MOUSE         1
826 #define OL_KM_TWEAK         2
827 #define OL_KM_SPECIALS      3
828
829 static short keymap_menu_type(short type)
830 {
831         if (ISKEYBOARD(type)) return OL_KM_KEYBOARD;
832         if (ISTWEAK(type)) return OL_KM_TWEAK;
833         if (ISMOUSE(type)) return OL_KM_MOUSE;
834 //      return OL_KM_SPECIALS;
835         return 0;
836 }
837
838 static const char *keymap_type_menu(void)
839 {
840         static const char string[] =
841             "Event Type%t"
842             "|Keyboard%x" STRINGIFY(OL_KM_KEYBOARD)
843             "|Mouse%x" STRINGIFY(OL_KM_MOUSE)
844             "|Tweak%x" STRINGIFY(OL_KM_TWEAK)
845 //      "|Specials%x" STRINGIFY(OL_KM_SPECIALS)
846         ;
847
848         return string;
849 }
850
851 static const char *keymap_mouse_menu(void)
852 {
853         static const char string[] =
854             "Mouse Event%t"
855             "|Left Mouse%x" STRINGIFY(LEFTMOUSE)
856             "|Middle Mouse%x" STRINGIFY(MIDDLEMOUSE)
857             "|Right Mouse%x" STRINGIFY(RIGHTMOUSE)
858             "|Middle Mouse%x" STRINGIFY(MIDDLEMOUSE)
859             "|Right Mouse%x" STRINGIFY(RIGHTMOUSE)
860             "|Button4 Mouse%x" STRINGIFY(BUTTON4MOUSE)
861             "|Button5 Mouse%x" STRINGIFY(BUTTON5MOUSE)
862             "|Action Mouse%x" STRINGIFY(ACTIONMOUSE)
863             "|Select Mouse%x" STRINGIFY(SELECTMOUSE)
864             "|Mouse Move%x" STRINGIFY(MOUSEMOVE)
865             "|Wheel Up%x" STRINGIFY(WHEELUPMOUSE)
866             "|Wheel Down%x" STRINGIFY(WHEELDOWNMOUSE)
867             "|Wheel In%x" STRINGIFY(WHEELINMOUSE)
868             "|Wheel Out%x" STRINGIFY(WHEELOUTMOUSE)
869             "|Mouse/Trackpad Pan%x" STRINGIFY(MOUSEPAN)
870             "|Mouse/Trackpad Zoom%x" STRINGIFY(MOUSEZOOM)
871             "|Mouse/Trackpad Rotate%x" STRINGIFY(MOUSEROTATE)
872         ;
873
874         return string;
875 }
876
877 static const char *keymap_tweak_menu(void)
878 {
879         static const char string[] =
880             "Tweak Event%t"
881             "|Left Mouse%x" STRINGIFY(EVT_TWEAK_L)
882             "|Middle Mouse%x" STRINGIFY(EVT_TWEAK_M)
883             "|Right Mouse%x" STRINGIFY(EVT_TWEAK_R)
884             "|Action Mouse%x" STRINGIFY(EVT_TWEAK_A)
885             "|Select Mouse%x" STRINGIFY(EVT_TWEAK_S)
886         ;
887
888         return string;
889 }
890
891 static const char *keymap_tweak_dir_menu(void)
892 {
893         static const char string[] =
894             "Tweak Direction%t"
895             "|Any%x" STRINGIFY(KM_ANY)
896             "|North%x" STRINGIFY(EVT_GESTURE_N)
897             "|North-East%x" STRINGIFY(EVT_GESTURE_NE)
898             "|East%x" STRINGIFY(EVT_GESTURE_E)
899             "|Sout-East%x" STRINGIFY(EVT_GESTURE_SE)
900             "|South%x" STRINGIFY(EVT_GESTURE_S)
901             "|South-West%x" STRINGIFY(EVT_GESTURE_SW)
902             "|West%x" STRINGIFY(EVT_GESTURE_W)
903             "|North-West%x" STRINGIFY(EVT_GESTURE_NW)
904         ;
905
906         return string;
907 }
908
909
910 static void keymap_type_cb(bContext *C, void *kmi_v, void *UNUSED(arg_v))
911 {
912         wmKeyMapItem *kmi = kmi_v;
913         short maptype = keymap_menu_type(kmi->type);
914         
915         if (maptype != kmi->maptype) {
916                 switch (kmi->maptype) {
917                         case OL_KM_KEYBOARD:
918                                 kmi->type = AKEY;
919                                 kmi->val = KM_PRESS;
920                                 break;
921                         case OL_KM_MOUSE:
922                                 kmi->type = LEFTMOUSE;
923                                 kmi->val = KM_PRESS;
924                                 break;
925                         case OL_KM_TWEAK:
926                                 kmi->type = EVT_TWEAK_L;
927                                 kmi->val = KM_ANY;
928                                 break;
929                         case OL_KM_SPECIALS:
930                                 kmi->type = AKEY;
931                                 kmi->val = KM_PRESS;
932                 }
933                 ED_region_tag_redraw(CTX_wm_region(C));
934         }
935 }
936
937 static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
938 {
939         TreeElement *te;
940         TreeStoreElem *tselem;
941         
942         uiBlockSetEmboss(block, UI_EMBOSST);
943         
944         for (te = lb->first; te; te = te->next) {
945                 tselem = TREESTORE(te);
946                 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
947                         uiBut *but;
948                         const char *str;
949                         int xstart = 240;
950                         int butw1 = UI_UNIT_X; /* operator */
951                         int butw2 = 90; /* event type, menus */
952                         int butw3 = 43; /* modifiers */
953
954                         if (tselem->type == TSE_KEYMAP_ITEM) {
955                                 wmKeyMapItem *kmi = te->directdata;
956                                 
957                                 /* modal map? */
958                                 if (kmi->propvalue) {
959                                         /* pass */
960                                 }
961                                 else {
962                                         uiDefBlockBut(block, operator_search_menu, kmi, "", xstart, (int)te->ys + 1, butw1, UI_UNIT_Y - 1,
963                                                       TIP_("Assign new Operator"));
964                                 }
965                                 xstart += butw1 + 10;
966                                 
967                                 /* map type button */
968                                 kmi->maptype = keymap_menu_type(kmi->type);
969                                 
970                                 str = keymap_type_menu();
971                                 but = uiDefButS(block, MENU, 0, str,    xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->maptype,
972                                                 0, 0, 0, 0, TIP_("Event type"));
973                                 uiButSetFunc(but, keymap_type_cb, kmi, NULL);
974                                 xstart += butw2 + 5;
975                                 
976                                 /* edit actual event */
977                                 switch (kmi->maptype) {
978                                         case OL_KM_KEYBOARD:
979                                                 uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
980                                                                 TIP_("Key code"));
981                                                 xstart += butw2 + 5;
982                                                 break;
983                                         case OL_KM_MOUSE:
984                                                 str = keymap_mouse_menu();
985                                                 uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
986                                                           0, 0, 0, 0, TIP_("Mouse button"));
987                                                 xstart += butw2 + 5;
988                                                 break;
989                                         case OL_KM_TWEAK:
990                                                 str = keymap_tweak_menu();
991                                                 uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
992                                                           0, 0, 0, 0, TIP_("Tweak gesture"));
993                                                 xstart += butw2 + 5;
994                                                 str = keymap_tweak_dir_menu();
995                                                 uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->val,
996                                                           0, 0, 0, 0, TIP_("Tweak gesture direction"));
997                                                 xstart += butw2 + 5;
998                                                 break;
999                                 }
1000                                 
1001                                 /* modifiers */
1002                                 uiDefButS(block, OPTION, 0, IFACE_("Shift"), xstart, (int)te->ys + 1, butw3 + 5, UI_UNIT_Y - 1,
1003                                           &kmi->shift, 0, 0, 0, 0, TIP_("Modifier"));
1004                                 xstart += butw3 + 5;
1005                                 uiDefButS(block, OPTION, 0, IFACE_("Ctrl"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->ctrl,
1006                                           0, 0, 0, 0, TIP_("Modifier"));
1007                                 xstart += butw3;
1008                                 uiDefButS(block, OPTION, 0, IFACE_("Alt"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->alt,
1009                                           0, 0, 0, 0, TIP_("Modifier"));
1010                                 xstart += butw3;
1011                                 uiDefButS(block, OPTION, 0, IFACE_("OS"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->oskey,
1012                                           0, 0, 0, 0, TIP_("Modifier"));
1013                                 xstart += butw3 + 5;
1014                                 uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->keymodifier,
1015                                                 TIP_("Key Modifier code"));
1016                                 xstart += butw3 + 5;
1017                                 
1018                                 /* rna property */
1019                                 if (kmi->ptr && kmi->ptr->data) {
1020                                         uiDefBut(block, LABEL, 0, IFACE_("(RNA property)"), xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1,
1021                                                  NULL, 0, 0, 0, 0, "");
1022                                         xstart += butw2;
1023                                 }
1024
1025                                 (void)xstart;
1026                         }
1027                 }
1028                 
1029                 if (TSELEM_OPEN(tselem, soops)) outliner_draw_keymapbuts(block, ar, soops, &te->subtree);
1030         }
1031
1032         uiBlockSetEmboss(block, UI_EMBOSS);
1033 }
1034
1035
1036 static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
1037 {
1038         uiBut *bt;
1039         TreeElement *te;
1040         TreeStoreElem *tselem;
1041         int spx, dx, len;
1042         
1043         for (te = lb->first; te; te = te->next) {
1044                 tselem = TREESTORE(te);
1045                 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
1046                         
1047                         if (tselem->flag & TSE_TEXTBUT) {
1048                                 
1049                                 /* If we add support to rename Sequence.
1050                                  * need change this.
1051                                  */
1052                                 // prevent crash when trying to rename 'pose' entry of armature
1053                                 if (tselem->type == TSE_POSE_BASE) continue;  
1054                                 
1055                                 if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name);
1056                                 else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name);
1057                                 else if (tselem->id && GS(tselem->id->name) == ID_LI) len = sizeof(((Library *) 0)->name);
1058                                 else len = MAX_ID_NAME - 2;
1059                                 
1060
1061                                 dx = (int)UI_GetStringWidth(te->name);
1062                                 if (dx < 5 * UI_UNIT_X) dx = 5 * UI_UNIT_X;
1063                                 spx = te->xs + 1.8f * UI_UNIT_X;
1064                                 if (spx + dx + 0.5f * UI_UNIT_X > ar->v2d.cur.xmax) dx = ar->v2d.cur.xmax - spx - 0.5f * UI_UNIT_X;
1065
1066                                 bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, (int)te->ys, dx + UI_UNIT_X, UI_UNIT_Y - 1, (void *)te->name,
1067                                               1.0, (float)len, 0, 0, "");
1068                                 uiButSetRenameFunc(bt, namebutton_cb, tselem);
1069                                 
1070                                 /* returns false if button got removed */
1071                                 if (false == uiButActiveOnly(C, ar, block, bt)) {
1072                                         tselem->flag &= ~TSE_TEXTBUT;
1073                                 }
1074                         }
1075                 }
1076                 
1077                 if (TSELEM_OPEN(tselem, soops)) outliner_buttons(C, block, ar, soops, &te->subtree);
1078         }
1079 }
1080
1081 /* ****************************************************** */
1082 /* Normal Drawing... */
1083
1084 /* make function calls a bit compacter */
1085 struct DrawIconArg {
1086         uiBlock *block;
1087         ID *id;
1088         float xmax, x, y, xb, yb;
1089         float alpha;
1090 };
1091
1092 static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
1093 {
1094         /* restrict column clip... it has been coded by simply overdrawing, doesnt work for buttons */
1095         if (arg->x >= arg->xmax) {
1096                 glEnable(GL_BLEND);
1097                 UI_icon_draw_aspect(arg->x, arg->y, icon, 1.0f / UI_DPI_FAC, arg->alpha);
1098                 glDisable(GL_BLEND);
1099         }
1100         else {
1101                 uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
1102                                           0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
1103                 
1104                 if (arg->id)
1105                         uiButSetDragID(but, arg->id);
1106         }
1107
1108 }
1109
1110 static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
1111                              float alpha)
1112 {
1113         struct DrawIconArg arg;
1114         float aspect;
1115         
1116         /* icons tiny bit away from text */
1117         x -= 0.15f * UI_UNIT_Y;
1118         
1119         /* make function calls a bit compacter */
1120         arg.block = block;
1121         arg.id = tselem->id;
1122         arg.xmax = xmax;
1123         arg.xb = x;     /* for ui buttons */
1124         arg.yb = y;
1125         arg.alpha = alpha;
1126         
1127         /* placement of icons, copied from interface_widgets.c */
1128         aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
1129         arg.x = x = x + 4.0f * aspect;
1130         arg.y = y = y + 0.1f * UI_UNIT_Y;
1131
1132         if (tselem->type) {
1133                 switch (tselem->type) {
1134                         case TSE_ANIM_DATA:
1135                                 UI_icon_draw(x, y, ICON_ANIM_DATA); break; // xxx
1136                         case TSE_NLA:
1137                                 UI_icon_draw(x, y, ICON_NLA); break;
1138                         case TSE_NLA_TRACK:
1139                                 UI_icon_draw(x, y, ICON_NLA); break; // XXX
1140                         case TSE_NLA_ACTION:
1141                                 UI_icon_draw(x, y, ICON_ACTION); break;
1142                         case TSE_DRIVER_BASE:
1143                                 UI_icon_draw(x, y, ICON_DRIVER); break;
1144                         case TSE_DEFGROUP_BASE:
1145                                 UI_icon_draw(x, y, ICON_GROUP_VERTEX); break;
1146                         case TSE_BONE:
1147                         case TSE_EBONE:
1148                                 UI_icon_draw(x, y, ICON_BONE_DATA); break;
1149                         case TSE_CONSTRAINT_BASE:
1150                                 UI_icon_draw(x, y, ICON_CONSTRAINT); break;
1151                         case TSE_MODIFIER_BASE:
1152                                 UI_icon_draw(x, y, ICON_MODIFIER); break;
1153                         case TSE_LINKED_OB:
1154                                 UI_icon_draw(x, y, ICON_OBJECT_DATA); break;
1155                         case TSE_LINKED_PSYS:
1156                                 UI_icon_draw(x, y, ICON_PARTICLES); break;
1157                         case TSE_MODIFIER:
1158                         {
1159                                 Object *ob = (Object *)tselem->id;
1160                                 ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
1161                                 switch ((ModifierType)md->type) {
1162                                         case eModifierType_Subsurf: 
1163                                                 UI_icon_draw(x, y, ICON_MOD_SUBSURF); break;
1164                                         case eModifierType_Armature: 
1165                                                 UI_icon_draw(x, y, ICON_MOD_ARMATURE); break;
1166                                         case eModifierType_Lattice: 
1167                                                 UI_icon_draw(x, y, ICON_MOD_LATTICE); break;
1168                                         case eModifierType_Curve: 
1169                                                 UI_icon_draw(x, y, ICON_MOD_CURVE); break;
1170                                         case eModifierType_Build: 
1171                                                 UI_icon_draw(x, y, ICON_MOD_BUILD); break;
1172                                         case eModifierType_Mirror: 
1173                                                 UI_icon_draw(x, y, ICON_MOD_MIRROR); break;
1174                                         case eModifierType_Decimate: 
1175                                                 UI_icon_draw(x, y, ICON_MOD_DECIM); break;
1176                                         case eModifierType_Wave: 
1177                                                 UI_icon_draw(x, y, ICON_MOD_WAVE); break;
1178                                         case eModifierType_Hook: 
1179                                                 UI_icon_draw(x, y, ICON_HOOK); break;
1180                                         case eModifierType_Softbody: 
1181                                                 UI_icon_draw(x, y, ICON_MOD_SOFT); break;
1182                                         case eModifierType_Boolean: 
1183                                                 UI_icon_draw(x, y, ICON_MOD_BOOLEAN); break;
1184                                         case eModifierType_ParticleSystem: 
1185                                                 UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
1186                                         case eModifierType_ParticleInstance:
1187                                                 UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
1188                                         case eModifierType_EdgeSplit:
1189                                                 UI_icon_draw(x, y, ICON_MOD_EDGESPLIT); break;
1190                                         case eModifierType_Array:
1191                                                 UI_icon_draw(x, y, ICON_MOD_ARRAY); break;
1192                                         case eModifierType_UVProject:
1193                                         case eModifierType_UVWarp:  /* TODO, get own icon */
1194                                                 UI_icon_draw(x, y, ICON_MOD_UVPROJECT); break;
1195                                         case eModifierType_Displace:
1196                                                 UI_icon_draw(x, y, ICON_MOD_DISPLACE); break;
1197                                         case eModifierType_Shrinkwrap:
1198                                                 UI_icon_draw(x, y, ICON_MOD_SHRINKWRAP); break;
1199                                         case eModifierType_Cast:
1200                                                 UI_icon_draw(x, y, ICON_MOD_CAST); break;
1201                                         case eModifierType_MeshDeform:
1202                                                 UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break;
1203                                         case eModifierType_Bevel:
1204                                                 UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
1205                                         case eModifierType_Smooth:
1206                                         case eModifierType_LaplacianSmooth:
1207                                                 UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
1208                                         case eModifierType_SimpleDeform:
1209                                                 UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
1210                                         case eModifierType_Mask:
1211                                                 UI_icon_draw(x, y, ICON_MOD_MASK); break;
1212                                         case eModifierType_Cloth:
1213                                                 UI_icon_draw(x, y, ICON_MOD_CLOTH); break;
1214                                         case eModifierType_Explode:
1215                                                 UI_icon_draw(x, y, ICON_MOD_EXPLODE); break;
1216                                         case eModifierType_Collision:
1217                                         case eModifierType_Surface:
1218                                                 UI_icon_draw(x, y, ICON_MOD_PHYSICS); break;
1219                                         case eModifierType_Fluidsim:
1220                                                 UI_icon_draw(x, y, ICON_MOD_FLUIDSIM); break;
1221                                         case eModifierType_Multires:
1222                                                 UI_icon_draw(x, y, ICON_MOD_MULTIRES); break;
1223                                         case eModifierType_Smoke:
1224                                                 UI_icon_draw(x, y, ICON_MOD_SMOKE); break;
1225                                         case eModifierType_Solidify:
1226                                                 UI_icon_draw(x, y, ICON_MOD_SOLIDIFY); break;
1227                                         case eModifierType_Screw:
1228                                                 UI_icon_draw(x, y, ICON_MOD_SCREW); break;
1229                                         case eModifierType_Remesh:
1230                                                 UI_icon_draw(x, y, ICON_MOD_REMESH); break;
1231                                         case eModifierType_WeightVGEdit:
1232                                         case eModifierType_WeightVGMix:
1233                                         case eModifierType_WeightVGProximity:
1234                                                 UI_icon_draw(x, y, ICON_MOD_VERTEX_WEIGHT); break;
1235                                         case eModifierType_DynamicPaint:
1236                                                 UI_icon_draw(x, y, ICON_MOD_DYNAMICPAINT); break;
1237                                         case eModifierType_Ocean:
1238                                                 UI_icon_draw(x, y, ICON_MOD_OCEAN); break;
1239                                         case eModifierType_Warp:
1240                                                 UI_icon_draw(x, y, ICON_MOD_WARP); break;
1241                                         case eModifierType_Skin:
1242                                                 UI_icon_draw(x, y, ICON_MOD_SKIN); break;
1243                                         case eModifierType_Triangulate:
1244                                                 UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break;
1245                                         case eModifierType_MeshCache:
1246                                                 UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break;  /* XXX, needs own icon */
1247                                         /* Default */
1248                                         case eModifierType_None:
1249                                         case eModifierType_ShapeKey:
1250                                         case NUM_MODIFIER_TYPES:
1251                                                 UI_icon_draw(x, y, ICON_DOT); break;
1252                                 }
1253                                 break;
1254                         }
1255                         case TSE_POSE_BASE:
1256                                 UI_icon_draw(x, y, ICON_ARMATURE_DATA); break;
1257                         case TSE_POSE_CHANNEL:
1258                                 UI_icon_draw(x, y, ICON_BONE_DATA); break;
1259                         case TSE_PROXY:
1260                                 UI_icon_draw(x, y, ICON_GHOST); break;
1261                         case TSE_R_LAYER_BASE:
1262                                 UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
1263                         case TSE_R_LAYER:
1264                                 UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
1265                         case TSE_LINKED_LAMP:
1266                                 UI_icon_draw(x, y, ICON_LAMP_DATA); break;
1267                         case TSE_LINKED_MAT:
1268                                 UI_icon_draw(x, y, ICON_MATERIAL_DATA); break;
1269                         case TSE_POSEGRP_BASE:
1270                                 UI_icon_draw(x, y, ICON_GROUP_BONE); break;
1271                         case TSE_SEQUENCE:
1272                                 if (te->idcode == SEQ_TYPE_MOVIE)
1273                                         UI_icon_draw(x, y, ICON_SEQUENCE);
1274                                 else if (te->idcode == SEQ_TYPE_META)
1275                                         UI_icon_draw(x, y, ICON_DOT);
1276                                 else if (te->idcode == SEQ_TYPE_SCENE)
1277                                         UI_icon_draw(x, y, ICON_SCENE);
1278                                 else if (te->idcode == SEQ_TYPE_SOUND_RAM)
1279                                         UI_icon_draw(x, y, ICON_SOUND);
1280                                 else if (te->idcode == SEQ_TYPE_IMAGE)
1281                                         UI_icon_draw(x, y, ICON_IMAGE_COL);
1282                                 else
1283                                         UI_icon_draw(x, y, ICON_PARTICLES);
1284                                 break;
1285                         case TSE_SEQ_STRIP:
1286                                 UI_icon_draw(x, y, ICON_LIBRARY_DATA_DIRECT);
1287                                 break;
1288                         case TSE_SEQUENCE_DUP:
1289                                 UI_icon_draw(x, y, ICON_OBJECT_DATA);
1290                                 break;
1291                         case TSE_RNA_STRUCT:
1292                                 if (RNA_struct_is_ID(te->rnaptr.type)) {
1293                                         arg.id = (ID *)te->rnaptr.data;
1294                                         tselem_draw_icon_uibut(&arg, RNA_struct_ui_icon(te->rnaptr.type));
1295                                 }
1296                                 else
1297                                         UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
1298                                 break;
1299                         default:
1300                                 UI_icon_draw(x, y, ICON_DOT); break;
1301                 }
1302         }
1303         else if (GS(tselem->id->name) == ID_OB) {
1304                 Object *ob = (Object *)tselem->id;
1305                 switch (ob->type) {
1306                         case OB_LAMP:
1307                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
1308                         case OB_MESH: 
1309                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
1310                         case OB_CAMERA: 
1311                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
1312                         case OB_CURVE: 
1313                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
1314                         case OB_MBALL: 
1315                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
1316                         case OB_LATTICE: 
1317                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
1318                         case OB_ARMATURE: 
1319                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
1320                         case OB_FONT: 
1321                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
1322                         case OB_SURF: 
1323                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
1324                         case OB_SPEAKER:
1325                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
1326                         case OB_EMPTY: 
1327                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break;
1328                 
1329                 }
1330         }
1331         else {
1332                 switch (GS(tselem->id->name)) {
1333                         case ID_SCE:
1334                                 tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
1335                         case ID_ME:
1336                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break;
1337                         case ID_CU:
1338                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break;
1339                         case ID_MB:
1340                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break;
1341                         case ID_LT:
1342                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break;
1343                         case ID_LA:
1344                         {
1345                                 Lamp *la = (Lamp *)tselem->id;
1346                                 
1347                                 switch (la->type) {
1348                                         case LA_LOCAL:
1349                                                 tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break;
1350                                         case LA_SUN:
1351                                                 tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break;
1352                                         case LA_SPOT:
1353                                                 tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break;
1354                                         case LA_HEMI:
1355                                                 tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break;
1356                                         case LA_AREA:
1357                                                 tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break;
1358                                         default:
1359                                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break;
1360                                 }
1361                                 break;
1362                         }
1363                         case ID_MA:
1364                                 tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break;
1365                         case ID_TE:
1366                                 tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break;
1367                         case ID_IM:
1368                                 tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break;
1369                         case ID_SPK:
1370                         case ID_SO:
1371                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break;
1372                         case ID_AR:
1373                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break;
1374                         case ID_CA:
1375                                 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break;
1376                         case ID_KE:
1377                                 tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break;
1378                         case ID_WO:
1379                                 tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break;
1380                         case ID_AC:
1381                                 tselem_draw_icon_uibut(&arg, ICON_ACTION); break;
1382                         case ID_NLA:
1383                                 tselem_draw_icon_uibut(&arg, ICON_NLA); break;
1384                         case ID_TXT:
1385                                 tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break;
1386                         case ID_GR:
1387                                 tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
1388                         case ID_LI:
1389                                 tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
1390                 }
1391         }
1392 }
1393
1394 static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level,
1395                                   int xmax, int *offsx, int ys)
1396 {
1397         TreeElement *te;
1398         TreeStoreElem *tselem;
1399         int active;
1400
1401         for (te = lb->first; te; te = te->next) {
1402                 
1403                 /* exit drawing early */
1404                 if ((*offsx) - UI_UNIT_X > xmax)
1405                         break;
1406
1407                 tselem = TREESTORE(te);
1408                 
1409                 /* object hierarchy always, further constrained on level */
1410                 if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) {
1411
1412                         /* active blocks get white circle */
1413                         if (tselem->type == 0) {
1414                                 if (te->idcode == ID_OB) {
1415                                         active = (OBACT == (Object *)tselem->id);
1416                                 }
1417                                 else if (scene->obedit && scene->obedit->data == tselem->id) {
1418                                         active = 1;  // XXX use context?
1419                                 }
1420                                 else {
1421                                         active = tree_element_active(C, scene, soops, te, 0);
1422                                 }
1423                         }
1424                         else {
1425                                 active = tree_element_type_active(NULL, scene, soops, te, tselem, 0, false);
1426                         }
1427
1428                         if (active) {
1429                                 float ufac = UI_UNIT_X / 20.0f;
1430
1431                                 uiSetRoundBox(UI_CNR_ALL);
1432                                 glColor4ub(255, 255, 255, 100);
1433                                 uiRoundBox((float) *offsx - 1.0f * ufac,
1434                                            (float)ys + 1.0f * ufac,
1435                                            (float)*offsx + UI_UNIT_X - 2.0f * ufac,
1436                                            (float)ys + UI_UNIT_Y - ufac,
1437                                            (float)UI_UNIT_Y / 2.0f - ufac);
1438                                 glEnable(GL_BLEND); /* roundbox disables */
1439                         }
1440                         
1441                         tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f);
1442                         te->xs = (float)*offsx;
1443                         te->ys = (float)ys;
1444                         te->xend = (short)*offsx + UI_UNIT_X;
1445                         te->flag |= TE_ICONROW; // for click
1446                         
1447                         (*offsx) += UI_UNIT_X;
1448                 }
1449                 
1450                 /* this tree element always has same amount of branches, so don't draw */
1451                 if (tselem->type != TSE_R_LAYER)
1452                         outliner_draw_iconrow(C, block, scene, soops, &te->subtree, level + 1, xmax, offsx, ys);
1453         }
1454         
1455 }
1456
1457 /* closed tree element */
1458 static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
1459 {
1460         TreeElement *ten;
1461         
1462         /* store coord and continue, we need coordinates for elements outside view too */
1463         te->xs = (float)startx;
1464         te->ys = (float)(*starty);
1465         
1466         for (ten = te->subtree.first; ten; ten = ten->next) {
1467                 outliner_set_coord_tree_element(soops, ten, startx + UI_UNIT_X, starty);
1468         }
1469 }
1470
1471
1472 static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops,
1473                                        TreeElement *te, int startx, int *starty)
1474 {
1475         TreeElement *ten;
1476         TreeStoreElem *tselem;
1477         float ufac = UI_UNIT_X / 20.0f;
1478         int offsx = 0, active = 0; // active=1 active obj, else active data
1479         
1480         tselem = TREESTORE(te);
1481
1482         if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) {
1483                 int xmax = ar->v2d.cur.xmax;
1484                 unsigned char alpha = 128;
1485                 
1486                 /* icons can be ui buts, we don't want it to overlap with restrict */
1487                 if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
1488                         xmax -= OL_TOGW + UI_UNIT_X;
1489                 
1490                 glEnable(GL_BLEND);
1491
1492                 /* start by highlighting search matches 
1493                  *      we don't expand items when searching in the datablocks but we 
1494                  *      still want to highlight any filter matches. 
1495                  */
1496                 if ((SEARCHING_OUTLINER(soops) || (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0)) &&
1497                     (tselem->flag & TSE_SEARCHMATCH))
1498                 {
1499                         char col[4];
1500                         UI_GetThemeColorType4ubv(TH_MATCH, SPACE_OUTLINER, col);
1501                         col[3] = alpha;
1502                         glColor4ubv((GLubyte *)col);
1503                         glRecti(startx, *starty + 1, ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
1504                 }
1505
1506                 /* colors for active/selected data */
1507                 if (tselem->type == 0) {
1508                         
1509                         if (te->idcode == ID_SCE) {
1510                                 if (tselem->id == (ID *)scene) {
1511                                         glColor4ub(255, 255, 255, alpha);
1512                                         active = 2;
1513                                 }
1514                         }
1515                         else if (te->idcode == ID_GR) {
1516                                 Group *gr = (Group *)tselem->id;
1517                                 if (group_select_flag(gr)) {
1518                                         char col[4];
1519                                         UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
1520                                         col[3] = alpha;
1521                                         glColor4ubv((GLubyte *)col);
1522                                         
1523                                         active = 2;
1524                                 }
1525                         }
1526                         else if (te->idcode == ID_OB) {
1527                                 Object *ob = (Object *)tselem->id;
1528                                 
1529                                 if (ob == OBACT || (ob->flag & SELECT)) {
1530                                         char col[4] = {0, 0, 0, 0};
1531                                         
1532                                         /* outliner active ob: always white text, circle color now similar to view3d */
1533                                         
1534                                         active = 2; /* means it draws a color circle */
1535                                         if (ob == OBACT) {
1536                                                 if (ob->flag & SELECT) {
1537                                                         UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
1538                                                         col[3] = alpha;
1539                                                 }
1540                                                 
1541                                                 active = 1; /* means it draws white text */
1542                                         }
1543                                         else if (ob->flag & SELECT) {
1544                                                 UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
1545                                                 col[3] = alpha;
1546                                         }
1547                                         
1548                                         glColor4ubv((GLubyte *)col);
1549                                 }
1550                         
1551                         }
1552                         else if (scene->obedit && scene->obedit->data == tselem->id) {
1553                                 glColor4ub(255, 255, 255, alpha);
1554                                 active = 2;
1555                         }
1556                         else {
1557                                 if (tree_element_active(C, scene, soops, te, 0)) {
1558                                         glColor4ub(220, 220, 255, alpha);
1559                                         active = 2;
1560                                 }
1561                         }
1562                 }
1563                 else {
1564                         if (tree_element_type_active(NULL, scene, soops, te, tselem, 0, false) ) active = 2;
1565                         glColor4ub(220, 220, 255, alpha);
1566                 }
1567                 
1568                 /* active circle */
1569                 if (active) {
1570                         uiSetRoundBox(UI_CNR_ALL);
1571                         uiRoundBox((float)startx + UI_UNIT_X,
1572                                    (float)*starty + 1.0f * ufac,
1573                                    (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
1574                                    (float)*starty + UI_UNIT_Y - 1.0f * ufac,
1575                                    UI_UNIT_Y / 2.0f - 1.0f * ufac);
1576                         glEnable(GL_BLEND); /* roundbox disables it */
1577                         
1578                         te->flag |= TE_ACTIVE; // for lookup in display hierarchies
1579                 }
1580                 
1581                 /* open/close icon, only when sublevels, except for scene */
1582                 if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
1583                         int icon_x;
1584                         if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE))
1585                                 icon_x = startx;
1586                         else
1587                                 icon_x = startx + 5 * ufac;
1588                         
1589                         // icons a bit higher
1590                         if (TSELEM_OPEN(tselem, soops))
1591                                 UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN);
1592                         else
1593                                 UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
1594                 }
1595                 offsx += UI_UNIT_X;
1596                 
1597                 /* datatype icon */
1598                 
1599                 if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))) {
1600                         
1601                         tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, 1.0f);
1602                         
1603                         offsx += UI_UNIT_X;
1604                 }
1605                 else
1606                         offsx += 2 * ufac;
1607                 
1608                 if (tselem->type == 0 && tselem->id->lib) {
1609                         glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
1610                         if (tselem->id->flag & LIB_INDIRECT)
1611                                 UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
1612                         else
1613                                 UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
1614                         glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1615                         offsx += UI_UNIT_X;
1616                 }
1617                 glDisable(GL_BLEND);
1618                 
1619                 /* name */
1620                 if (active == 1) UI_ThemeColor(TH_TEXT_HI);
1621                 else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
1622                 else UI_ThemeColor(TH_TEXT);
1623                 
1624                 UI_DrawString(startx + offsx, *starty + 5 * ufac, te->name);
1625                 
1626                 offsx += (int)(UI_UNIT_X + UI_GetStringWidth(te->name));
1627                 
1628                 /* closed item, we draw the icons, not when it's a scene, or master-server list though */
1629                 if (!TSELEM_OPEN(tselem, soops)) {
1630                         if (te->subtree.first) {
1631                                 if (tselem->type == 0 && te->idcode == ID_SCE) {
1632                                         /* pass */
1633                                 }
1634                                 else if (tselem->type != TSE_R_LAYER) {
1635                                         /* this tree element always has same amount of branches, so don't draw */
1636
1637                                         int tempx = startx + offsx;
1638                                         
1639                                         /* divider */
1640                                         UI_ThemeColorShade(TH_BACK, -40);
1641                                         glRecti(tempx   - 10.0f * ufac,
1642                                                 *starty +  4.0f * ufac,
1643                                                 tempx   -  8.0f * ufac,
1644                                                 *starty + UI_UNIT_Y - 4.0f * ufac);
1645                                         
1646                                         glEnable(GL_BLEND);
1647                                         glPixelTransferf(GL_ALPHA_SCALE, 0.5);
1648                                         
1649                                         outliner_draw_iconrow(C, block, scene, soops, &te->subtree, 0, xmax, &tempx, *starty);
1650                                         
1651                                         glPixelTransferf(GL_ALPHA_SCALE, 1.0);
1652                                         glDisable(GL_BLEND);
1653                                 }
1654                         }
1655                 }
1656         }
1657         /* store coord and continue, we need coordinates for elements outside view too */
1658         te->xs = (float)startx;
1659         te->ys = (float)*starty;
1660         te->xend = startx + offsx;
1661                 
1662         if (TSELEM_OPEN(tselem, soops)) {
1663                 *starty -= UI_UNIT_Y;
1664                 
1665                 for (ten = te->subtree.first; ten; ten = ten->next)
1666                         outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty);
1667         }
1668         else {
1669                 for (ten = te->subtree.first; ten; ten = ten->next)
1670                         outliner_set_coord_tree_element(soops, te, startx, starty);
1671                 
1672                 *starty -= UI_UNIT_Y;
1673         }
1674 }
1675
1676 static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty)
1677 {
1678         TreeElement *te;
1679         TreeStoreElem *tselem;
1680         int y1, y2;
1681         
1682         if (lb->first == NULL) return;
1683         
1684         y1 = y2 = *starty; /* for vertical lines between objects */
1685         for (te = lb->first; te; te = te->next) {
1686                 y2 = *starty;
1687                 tselem = TREESTORE(te);
1688                 
1689                 /* horizontal line? */
1690                 if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE))
1691                         glRecti(startx, *starty, startx + UI_UNIT_X, *starty - 1);
1692                         
1693                 *starty -= UI_UNIT_Y;
1694                 
1695                 if (TSELEM_OPEN(tselem, soops))
1696                         outliner_draw_hierarchy(soops, &te->subtree, startx + UI_UNIT_X, starty);
1697         }
1698         
1699         /* vertical line */
1700         te = lb->last;
1701         if (te->parent || lb->first != lb->last) {
1702                 tselem = TREESTORE(te);
1703                 if (tselem->type == 0 && te->idcode == ID_OB) {
1704                         
1705                         glRecti(startx, y1 + UI_UNIT_Y, startx + 1, y2);
1706                 }
1707         }
1708 }
1709
1710 static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty) 
1711 {
1712         TreeElement *te;
1713         TreeStoreElem *tselem;
1714         
1715         for (te = lb->first; te; te = te->next) {
1716                 tselem = TREESTORE(te);
1717                 
1718                 /* selection status */
1719                 if (TSELEM_OPEN(tselem, soops))
1720                         if (tselem->type == TSE_RNA_STRUCT)
1721                                 glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
1722
1723                 *starty -= UI_UNIT_Y;
1724                 if (TSELEM_OPEN(tselem, soops)) {
1725                         outliner_draw_struct_marks(ar, soops, &te->subtree, starty);
1726                         if (tselem->type == TSE_RNA_STRUCT)
1727                                 fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y);
1728                 }
1729         }
1730 }
1731
1732 static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty) 
1733 {
1734         TreeElement *te;
1735         TreeStoreElem *tselem;
1736         
1737         for (te = lb->first; te; te = te->next) {
1738                 tselem = TREESTORE(te);
1739                 
1740                 /* selection status */
1741                 if (tselem->flag & TSE_SELECTED) {
1742                         glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
1743                 }
1744                 *starty -= UI_UNIT_Y;
1745                 if (TSELEM_OPEN(tselem, soops)) outliner_draw_selection(ar, soops, &te->subtree, starty);
1746         }
1747 }
1748
1749
1750 static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops)
1751 {
1752         TreeElement *te;
1753         int starty, startx;
1754         float col[3];
1755                 
1756         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); // only once
1757         
1758         if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
1759                 /* struct marks */
1760                 UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
1761                 //UI_ThemeColorShade(TH_BACK, -20);
1762                 starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1763                 outliner_draw_struct_marks(ar, soops, &soops->tree, &starty);
1764         }
1765         
1766         /* always draw selection fill before hierarchy */
1767         UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col);
1768         glColor3fv(col);
1769         starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1770         outliner_draw_selection(ar, soops, &soops->tree, &starty);
1771         
1772         // gray hierarchy lines
1773         UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.4f);
1774         starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
1775         startx = 6;
1776         outliner_draw_hierarchy(soops, &soops->tree, startx, &starty);
1777         
1778         // items themselves
1779         starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1780         startx = 0;
1781         for (te = soops->tree.first; te; te = te->next) {
1782                 outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty);
1783         }
1784 }
1785
1786
1787 static void outliner_back(ARegion *ar)
1788 {
1789         int ystart;
1790         
1791         UI_ThemeColorShade(TH_BACK, 6);
1792         ystart = (int)ar->v2d.tot.ymax;
1793         ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
1794         
1795         while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) {
1796                 glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
1797                 ystart -= 2 * UI_UNIT_Y;
1798         }
1799 }
1800
1801 static void outliner_draw_restrictcols(ARegion *ar)
1802 {
1803         int ystart;
1804         
1805         /* background underneath */
1806         UI_ThemeColor(TH_BACK);
1807         glRecti((int)(ar->v2d.cur.xmax - OL_TOGW),
1808                 (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax);
1809         
1810         UI_ThemeColorShade(TH_BACK, 6);
1811         ystart = (int)ar->v2d.tot.ymax;
1812         ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
1813         
1814         while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) {
1815                 glRecti((int)ar->v2d.cur.xmax - OL_TOGW, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
1816                 ystart -= 2 * UI_UNIT_Y;
1817         }
1818         
1819         UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
1820
1821         /* view */
1822         sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
1823                   (int)ar->v2d.cur.ymax,
1824                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
1825                   (int)ar->v2d.cur.ymin);
1826
1827         /* render */
1828         sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
1829                   (int)ar->v2d.cur.ymax,
1830                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
1831                   (int)ar->v2d.cur.ymin);
1832
1833         /* render */
1834         sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
1835                   (int)ar->v2d.cur.ymax,
1836                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
1837                   (int)ar->v2d.cur.ymin);
1838 }
1839
1840 /* ****************************************************** */
1841 /* Main Entrypoint - Draw contents of Outliner editor */
1842
1843 void draw_outliner(const bContext *C)
1844 {
1845         Main *mainvar = CTX_data_main(C); 
1846         Scene *scene = CTX_data_scene(C);
1847         ARegion *ar = CTX_wm_region(C);
1848         View2D *v2d = &ar->v2d;
1849         SpaceOops *soops = CTX_wm_space_outliner(C);
1850         uiBlock *block;
1851         int sizey = 0, sizex = 0, sizex_rna = 0;
1852
1853         outliner_build_tree(mainvar, scene, soops); // always
1854         
1855         /* get extents of data */
1856         outliner_height(soops, &soops->tree, &sizey);
1857
1858         if (ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP)) {
1859                 /* RNA has two columns:
1860                  *  - column 1 is (max_width + OL_RNA_COL_SPACEX) or
1861                  *                               (OL_RNA_COL_X), whichever is wider...
1862                  *      - column 2 is fixed at OL_RNA_COL_SIZEX
1863                  *
1864                  *  (*) XXX max width for now is a fixed factor of (UI_UNIT_X * (max_indention + 100))
1865                  */
1866                  
1867                 /* get actual width of column 1 */
1868                 outliner_rna_width(soops, &soops->tree, &sizex_rna, 0);
1869                 sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX);
1870                 
1871                 /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */
1872                 if (soops->outlinevis == SO_KEYMAP)
1873                         // XXX this is only really a quick hack to make this wide enough...
1874                         sizex = sizex_rna + OL_RNA_COL_SIZEX * 3 + 50;
1875                 else
1876                         sizex = sizex_rna + OL_RNA_COL_SIZEX + 50;
1877         }
1878         else {
1879                 /* width must take into account restriction columns (if visible) so that entries will still be visible */
1880                 //outliner_width(soops, &soops->tree, &sizex);
1881                 // XXX should use outliner_width instead when te->xend will be set correctly...
1882                 outliner_rna_width(soops, &soops->tree, &sizex, 0);
1883                 
1884                 /* constant offset for restriction columns */
1885                 // XXX this isn't that great yet...
1886                 if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
1887                         sizex += OL_TOGW * 3;
1888                 
1889         }
1890         
1891         /* adds vertical offset */
1892         sizey += OL_Y_OFFSET;
1893
1894         /* update size of tot-rect (extents of data/viewable area) */
1895         UI_view2d_totRect_set(v2d, sizex, sizey);
1896
1897         /* force display to pixel coords */
1898         v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y);
1899         /* set matrix for 2d-view controls */
1900         UI_view2d_view_ortho(v2d);
1901
1902         /* draw outliner stuff (background, hierachy lines and names) */
1903         outliner_back(ar);
1904         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1905         outliner_draw_tree((bContext *)C, block, scene, ar, soops);
1906         
1907         if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
1908                 /* draw rna buttons */
1909                 outliner_draw_rnacols(ar, sizex_rna);
1910                 outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
1911         }
1912         else if (soops->outlinevis == SO_KEYMAP) {
1913                 outliner_draw_keymapbuts(block, ar, soops, &soops->tree);
1914         }
1915         else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) {
1916                 /* draw restriction columns */
1917                 outliner_draw_restrictcols(ar);
1918                 outliner_draw_restrictbuts(block, scene, ar, soops, &soops->tree);
1919         }
1920
1921         /* draw edit buttons if nessecery */
1922         outliner_buttons(C, block, ar, soops, &soops->tree);
1923
1924         uiEndBlock(C, block);
1925         uiDrawBlock(C, block);
1926
1927         /* clear flag that allows quick redraws */
1928         soops->storeflag &= ~SO_TREESTORE_REDRAW;
1929