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