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