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