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