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