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