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