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