diff options
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_draw.c')
-rw-r--r-- | source/blender/editors/space_outliner/outliner_draw.c | 601 |
1 files changed, 224 insertions, 377 deletions
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 3de786ddd4d..22bb99530dc 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -42,6 +42,7 @@ #include "BLT_translation.h" +#include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_fcurve.h" @@ -108,7 +109,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner, } } -static void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height) +void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height) { *r_width = 0; *r_height = 0; @@ -849,8 +850,8 @@ typedef struct RestrictProperties { PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; PropertyRNA *base_hide_viewport; PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; - PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only, - *layer_collection_hide_viewport; + PropertyRNA *layer_collection_exclude, *layer_collection_holdout, + *layer_collection_indirect_only, *layer_collection_hide_viewport; PropertyRNA *modifier_show_viewport, *modifier_show_render; PropertyRNA *constraint_enable; PropertyRNA *bone_hide_viewport; @@ -866,6 +867,7 @@ typedef struct RestrictPropertiesActive { bool collection_hide_viewport; bool collection_hide_select; bool collection_hide_render; + bool layer_collection_exclude; bool layer_collection_holdout; bool layer_collection_indirect_only; bool layer_collection_hide_viewport; @@ -941,6 +943,20 @@ static void outliner_restrict_properties_enable_layer_collection_set( props_active->object_hide_select = false; } } + + if (props_active->layer_collection_exclude) { + props_active->layer_collection_exclude = !RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_exclude); + + if (!props_active->layer_collection_exclude) { + props_active->collection_hide_viewport = false; + props_active->collection_hide_select = false; + props_active->collection_hide_render = false; + props_active->layer_collection_hide_viewport = false; + props_active->layer_collection_holdout = false; + props_active->layer_collection_indirect_only = false; + } + } } static bool outliner_restrict_properties_collection_set(Scene *scene, @@ -955,8 +971,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene, NULL; Collection *collection = outliner_collection_from_tree_element(te); - if ((collection->flag & COLLECTION_IS_MASTER) || - (layer_collection && ((layer_collection->flag & LAYER_COLLECTION_EXCLUDE) != 0))) { + if (collection->flag & COLLECTION_IS_MASTER) { return false; } @@ -996,6 +1011,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, "hide_viewport"); props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); + props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection, + "exclude"); props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection, "holdout"); props.layer_collection_indirect_only = RNA_struct_type_find_property(&RNA_LayerCollection, @@ -1013,6 +1030,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } struct { + int enable; int select; int hide; int viewport; @@ -1043,6 +1061,11 @@ static void outliner_draw_restrictbuts(uiBlock *block, if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) { restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; } + if (space_outliner->outlinevis == SO_VIEW_LAYER && + space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) { + restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) == outliner_restrict_columns_width(space_outliner)); @@ -1435,6 +1458,26 @@ static void outliner_draw_restrictbuts(uiBlock *block, Collection *collection = outliner_collection_from_tree_element(te); if (layer_collection != NULL) { + if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(region->v2d.cur.xmax) - restrict_offsets.enable, + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_exclude, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, @@ -1828,7 +1871,6 @@ static void outliner_buttons(const bContext *C, const float restrict_column_width, TreeElement *te) { - SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); uiBut *bt; TreeStoreElem *tselem; int spx, dx, len; @@ -1854,10 +1896,6 @@ static void outliner_buttons(const bContext *C, } spx = te->xs + 1.8f * UI_UNIT_X; - if ((tselem->type == TSE_LAYER_COLLECTION) && - (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) { - spx += UI_UNIT_X; - } dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X); bt = uiDefBut(block, @@ -1897,8 +1935,14 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED return; } + /* Check that the the item is actually an object. */ + BLI_assert(tselem->id != NULL && GS(tselem->id->name) == ID_OB); + + Object *ob = (Object *)tselem->id; + const bool object_data_shared = (ob->data == tvc.obact->data); + wmWindow *win = CTX_wm_window(C); - const bool do_extend = win->eventstate->ctrl != 0; + const bool do_extend = win->eventstate->ctrl != 0 && !object_data_shared; outliner_item_mode_toggle(C, &tvc, te, do_extend); } @@ -1909,60 +1953,71 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, TreeStoreElem *tselem, const bool lock_object_modes) { - const int active_mode = tvc->obact->mode; - bool draw_active_icon = true; + if (tselem->type != 0 || te->idcode != ID_OB) { + return; + } - if (tselem->type == 0 && te->idcode == ID_OB) { - Object *ob = (Object *)tselem->id; + Object *ob = (Object *)tselem->id; + Object *ob_active = tvc->obact; - /* When not locking object modes, objects can remain in non-object modes. For modes that do not - * allow multi-object editing, these other objects should still show be viewed as not in the - * mode. Otherwise multiple objects show the same mode icon in the outliner even though only - * one object is actually editable in the mode. */ - if (!lock_object_modes && ob != tvc->obact && !(tvc->ob_edit || tvc->ob_pose)) { - draw_active_icon = false; - } + /* Not all objects support particle systems. */ + if (ob_active->mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) { + return; + } - if (ob->type == tvc->obact->type) { - int icon; - const char *tip; + /* Only for objects with the same type. */ + if (ob->type != ob_active->type) { + return; + } - if (draw_active_icon && ob->mode == tvc->obact->mode) { - icon = UI_mode_icon_get(active_mode); - tip = TIP_("Remove from the current mode"); - } - else { - /* Not all objects support particle systems */ - if (active_mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) { - return; - } - icon = ICON_DOT; - tip = TIP_( - "Change the object in the current mode\n" - "* Ctrl to add to the current mode"); - } + bool draw_active_icon = ob->mode == ob_active->mode; - uiBut *but = uiDefIconBut(block, - UI_BTYPE_ICON_TOGGLE, - 0, - icon, - 0, - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - tip); - UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); - UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); - - if (ID_IS_LINKED(&ob->id)) { - UI_but_disable(but, TIP_("Can't edit external library data")); - } - } + /* When not locking object modes, objects can remain in non-object modes. For modes that do not + * allow multi-object editing, these other objects should still show be viewed as not in the + * mode. Otherwise multiple objects show the same mode icon in the outliner even though only + * one object is actually editable in the mode. */ + if (!lock_object_modes && ob != ob_active && !(tvc->ob_edit || tvc->ob_pose)) { + draw_active_icon = false; + } + + const bool object_data_shared = (ob->data == ob_active->data); + draw_active_icon = draw_active_icon || object_data_shared; + + int icon; + const char *tip; + if (draw_active_icon) { + icon = UI_icon_from_object_mode(ob_active->mode); + tip = object_data_shared ? TIP_("Change the object in the current mode") : + TIP_("Remove from the current mode"); + } + else { + icon = ICON_DOT; + tip = TIP_( + "Change the object in the current mode\n" + "* Ctrl to add to the current mode"); + } + + uiBut *but = uiDefIconBut(block, + UI_BTYPE_ICON_TOGGLE, + 0, + icon, + 0, + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + tip); + UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); + UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); + /* Mode toggling handles it's own undo state because undo steps need to be grouped. */ + UI_but_flag_disable(but, UI_BUT_UNDO); + + if (ID_IS_LINKED(&ob->id)) { + UI_but_disable(but, TIP_("Can't edit external library data")); } } @@ -2024,9 +2079,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) break; case TSE_CONSTRAINT_BASE: data.icon = ICON_CONSTRAINT; + data.drag_id = tselem->id; break; case TSE_CONSTRAINT: { bConstraint *con = te->directdata; + data.drag_id = tselem->id; switch ((eBConstraint_Types)con->type) { case CONSTRAINT_TYPE_CAMERASOLVER: data.icon = ICON_CON_CAMERASOLVER; @@ -2121,6 +2178,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } case TSE_MODIFIER_BASE: data.icon = ICON_MODIFIER_DATA; + data.drag_id = tselem->id; break; case TSE_LINKED_OB: data.icon = ICON_OBJECT_DATA; @@ -2130,165 +2188,16 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) break; case TSE_MODIFIER: { Object *ob = (Object *)tselem->id; + data.drag_id = tselem->id; + if (ob->type != OB_GPENCIL) { ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); - switch ((ModifierType)md->type) { - case eModifierType_Subsurf: - data.icon = ICON_MOD_SUBSURF; - break; - case eModifierType_Armature: - data.icon = ICON_MOD_ARMATURE; - break; - case eModifierType_Lattice: - data.icon = ICON_MOD_LATTICE; - break; - case eModifierType_Curve: - data.icon = ICON_MOD_CURVE; - break; - case eModifierType_Build: - data.icon = ICON_MOD_BUILD; - break; - case eModifierType_Mirror: - data.icon = ICON_MOD_MIRROR; - break; - case eModifierType_Decimate: - data.icon = ICON_MOD_DECIM; - break; - case eModifierType_Wave: - data.icon = ICON_MOD_WAVE; - break; - case eModifierType_Hook: - data.icon = ICON_HOOK; - break; - case eModifierType_Softbody: - data.icon = ICON_MOD_SOFT; - break; - case eModifierType_Boolean: - data.icon = ICON_MOD_BOOLEAN; - break; - case eModifierType_ParticleSystem: - data.icon = ICON_MOD_PARTICLES; - break; - case eModifierType_ParticleInstance: - data.icon = ICON_MOD_PARTICLES; - break; - case eModifierType_EdgeSplit: - data.icon = ICON_MOD_EDGESPLIT; - break; - case eModifierType_Array: - data.icon = ICON_MOD_ARRAY; - break; - case eModifierType_UVProject: - case eModifierType_UVWarp: /* TODO, get own icon */ - data.icon = ICON_MOD_UVPROJECT; - break; - case eModifierType_Displace: - data.icon = ICON_MOD_DISPLACE; - break; - case eModifierType_Shrinkwrap: - data.icon = ICON_MOD_SHRINKWRAP; - break; - case eModifierType_Cast: - data.icon = ICON_MOD_CAST; - break; - case eModifierType_MeshDeform: - case eModifierType_SurfaceDeform: - data.icon = ICON_MOD_MESHDEFORM; - break; - case eModifierType_Bevel: - data.icon = ICON_MOD_BEVEL; - break; - case eModifierType_Smooth: - case eModifierType_LaplacianSmooth: - case eModifierType_CorrectiveSmooth: - data.icon = ICON_MOD_SMOOTH; - break; - case eModifierType_SimpleDeform: - data.icon = ICON_MOD_SIMPLEDEFORM; - break; - case eModifierType_Mask: - data.icon = ICON_MOD_MASK; - break; - case eModifierType_Cloth: - data.icon = ICON_MOD_CLOTH; - break; - case eModifierType_Explode: - data.icon = ICON_MOD_EXPLODE; - break; - case eModifierType_Collision: - case eModifierType_Surface: - data.icon = ICON_MOD_PHYSICS; - break; - case eModifierType_Fluidsim: /* deprecated, old fluid modifier */ - data.icon = ICON_MOD_FLUIDSIM; - break; - case eModifierType_Multires: - data.icon = ICON_MOD_MULTIRES; - break; - case eModifierType_Fluid: - data.icon = ICON_MOD_FLUID; - break; - case eModifierType_Solidify: - data.icon = ICON_MOD_SOLIDIFY; - break; - case eModifierType_Screw: - data.icon = ICON_MOD_SCREW; - break; - case eModifierType_Remesh: - data.icon = ICON_MOD_REMESH; - break; - case eModifierType_WeightVGEdit: - case eModifierType_WeightVGMix: - case eModifierType_WeightVGProximity: - data.icon = ICON_MOD_VERTEX_WEIGHT; - break; - case eModifierType_DynamicPaint: - data.icon = ICON_MOD_DYNAMICPAINT; - break; - case eModifierType_Ocean: - data.icon = ICON_MOD_OCEAN; - break; - case eModifierType_Warp: - data.icon = ICON_MOD_WARP; - break; - case eModifierType_Skin: - data.icon = ICON_MOD_SKIN; - break; - case eModifierType_Triangulate: - data.icon = ICON_MOD_TRIANGULATE; - break; - case eModifierType_MeshCache: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_MeshSequenceCache: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_Wireframe: - data.icon = ICON_MOD_WIREFRAME; - break; - case eModifierType_Weld: - data.icon = ICON_AUTOMERGE_OFF; /* XXX, needs own icon */ - break; - case eModifierType_LaplacianDeform: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_DataTransfer: - data.icon = ICON_MOD_DATA_TRANSFER; - break; - case eModifierType_NormalEdit: - case eModifierType_WeightedNormal: - data.icon = ICON_MOD_NORMALEDIT; - break; - case eModifierType_Simulation: - data.icon = ICON_PHYSICS; /* TODO: Use correct icon. */ - break; - /* Default */ - case eModifierType_None: - case eModifierType_ShapeKey: - - case NUM_MODIFIER_TYPES: - data.icon = ICON_DOT; - break; + const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(md->type); + if (modifier_type != NULL) { + data.icon = modifier_type->icon; + } + else { + data.icon = ICON_DOT; } } else { @@ -2464,7 +2373,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; } - data.icon = ICON_GROUP; + data.icon = ICON_OUTLINER_COLLECTION; break; } case TSE_GP_LAYER: { @@ -2700,60 +2609,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) return data; } -static void tselem_draw_layer_collection_enable_icon( - Scene *scene, uiBlock *block, int xmax, float x, float y, TreeElement *te, float alpha) -{ - /* Get RNA property (once for speed). */ - static PropertyRNA *exclude_prop = NULL; - if (exclude_prop == NULL) { - exclude_prop = RNA_struct_type_find_property(&RNA_LayerCollection, "exclude"); - } - - if (x >= xmax) { - /* Placement of icons, copied from interface_widgets.c. */ - float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; - x += 2.0f * aspect; - y += 2.0f * aspect; - - /* restrict column clip... it has been coded by simply overdrawing, - * doesn't work for buttons */ - uchar color[4]; - int icon = RNA_property_ui_icon(exclude_prop); - if (UI_icon_get_theme_color(icon, color)) { - UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, color, true); - } - else { - UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); - } - } - else { - LayerCollection *layer_collection = te->directdata; - PointerRNA layer_collection_ptr; - RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); - - char emboss = UI_block_emboss_get(block); - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiBut *bt = uiDefIconButR_prop(block, - UI_BTYPE_ICON_TOGGLE, - 0, - 0, - x, - y, - UI_UNIT_X, - UI_UNIT_Y, - &layer_collection_ptr, - exclude_prop, - -1, - 0, - 0, - 0, - 0, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_block_emboss_set(block, emboss); - } -} - static void tselem_draw_icon(uiBlock *block, int xmax, float x, @@ -2764,21 +2619,38 @@ static void tselem_draw_icon(uiBlock *block, const bool is_clickable) { TreeElementIcon data = tree_element_get_icon(tselem, te); - if (data.icon == 0) { return; } - /* Icon is covered by restrict buttons */ - if (!is_clickable || x >= xmax) { - /* Reduce alpha to match icon buttons */ - alpha *= 0.8f; + const bool is_collection = outliner_is_collection_tree_element(te); + /* Collection colors and icons covered by restrict buttons. */ + if (!is_clickable || x >= xmax || is_collection) { /* placement of icons, copied from interface_widgets.c */ float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; x += 2.0f * aspect; y += 2.0f * aspect; + if (is_collection) { + Collection *collection = outliner_collection_from_tree_element(te); + if (collection->color_tag != COLLECTION_COLOR_NONE) { + bTheme *btheme = UI_GetTheme(); + UI_icon_draw_ex(x, + y, + data.icon, + U.inv_dpi_fac, + alpha, + 0.0f, + btheme->collection_color[collection->color_tag].color, + true); + return; + } + } + + /* Reduce alpha to match icon buttons */ + alpha *= 0.8f; + /* restrict column clip... it has been coded by simply overdrawing, * doesn't work for buttons */ uchar color[4]; @@ -3060,9 +2932,9 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta /* closed items may be displayed in row of parent, don't change their coordinate! */ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) { - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = startx; - te->ys = starty; + te->xs = 0; + te->ys = 0; + te->xend = 0; } for (ten = te->subtree.first; ten; ten = ten->next) { @@ -3166,15 +3038,6 @@ static void outliner_draw_tree_element(bContext *C, else { active = tree_element_type_active(C, tvc, space_outliner, te, tselem, OL_SETSEL_NONE, false); /* active collection*/ - icon_bgcolor[3] = 0.2f; - } - - /* Checkbox to enable collections. */ - if ((tselem->type == TSE_LAYER_COLLECTION) && - (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) { - tselem_draw_layer_collection_enable_icon( - tvc->scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f); - offsx += UI_UNIT_X; } /* active circle */ @@ -3225,7 +3088,7 @@ static void outliner_draw_tree_element(bContext *C, if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) || ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) { - const BIFIconID lib_icon = UI_library_icon_get(tselem->id); + const BIFIconID lib_icon = UI_icon_from_library(tselem->id); if (lib_icon != ICON_NONE) { UI_icon_draw_alpha( (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac); @@ -3312,6 +3175,34 @@ static void outliner_draw_tree_element(bContext *C, } } +static bool subtree_contains_object(ListBase *lb) +{ + LISTBASE_FOREACH (TreeElement *, te, lb) { + TreeStoreElem *tselem = TREESTORE(te); + if (tselem->type == 0 && te->idcode == ID_OB) { + return true; + } + } + return false; +} + +static void outliner_draw_hierarchy_line( + const uint pos, const int x, const int y1, const int y2, const bool draw_dashed) +{ + /* Small vertical padding. */ + const short line_padding = UI_UNIT_Y / 4.0f; + + /* >= is 1.0 for undashed lines. */ + immUniform1f("dash_factor", draw_dashed ? 0.5f : 1.0f); + + immBegin(GPU_PRIM_LINES, 2); + /* Intentionally draw from top to bottom, so collapsing a child item doesn't make the dashes + * appear to move. */ + immVertex2f(pos, x, y2 + line_padding); + immVertex2f(pos, x, y1 - line_padding); + immEnd(); +} + static void outliner_draw_hierarchy_lines_recursive(uint pos, SpaceOutliner *space_outliner, ListBase *lb, @@ -3320,100 +3211,50 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos, bool draw_grayed_out, int *starty) { - TreeElement *te, *te_vertical_line_last = NULL, *te_vertical_line_last_dashed = NULL; - int y1, y2, y1_dashed, y2_dashed; - - if (BLI_listbase_is_empty(lb)) { - return; - } + bTheme *btheme = UI_GetTheme(); + int y = *starty; - struct { - int steps_num; - int step_len; - int gap_len; - } dash = { - .steps_num = 4, - }; - - dash.step_len = UI_UNIT_X / dash.steps_num; - dash.gap_len = dash.step_len / 2; - - const uchar grayed_alpha = col[3] / 2; - - /* For vertical lines between objects. */ - y1 = y2 = y1_dashed = y2_dashed = *starty; - for (te = lb->first; te; te = te->next) { - bool draw_children_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING); + /* Draw vertical lines between collections */ + bool draw_hierarchy_line; + bool is_object_line; + LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); + draw_hierarchy_line = false; + is_object_line = false; + *starty -= UI_UNIT_Y; + short color_tag = COLLECTION_COLOR_NONE; - if (draw_children_grayed_out) { - immUniformColor3ubvAlpha(col, grayed_alpha); - } - else { - immUniformColor4ubv(col); - } + /* Only draw hierarchy lines for expanded collections and objects with children. */ + if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) { + if (tselem->type == TSE_LAYER_COLLECTION) { + draw_hierarchy_line = true; - if ((te->flag & TE_CHILD_NOT_IN_COLLECTION) == 0) { - /* Horizontal Line? */ - if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) { - immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - U.pixelsize); + Collection *collection = outliner_collection_from_tree_element(te); + color_tag = collection->color_tag; - /* Vertical Line? */ - if (te->idcode == ID_OB) { - te_vertical_line_last = te; - y2 = *starty; - } - y1_dashed = *starty - UI_UNIT_Y; + y = *starty; } - } - else { - BLI_assert(te->idcode == ID_OB); - /* Horizontal line - dashed. */ - int start = startx; - for (int i = 0; i < dash.steps_num; i++) { - immRecti(pos, start, *starty, start + dash.step_len - dash.gap_len, *starty - U.pixelsize); - start += dash.step_len; + else if (tselem->type == 0 && te->idcode == ID_OB) { + if (subtree_contains_object(&te->subtree)) { + draw_hierarchy_line = true; + is_object_line = true; + y = *starty; + } } - te_vertical_line_last_dashed = te; - y2_dashed = *starty; + outliner_draw_hierarchy_lines_recursive( + pos, space_outliner, &te->subtree, startx + UI_UNIT_X, col, draw_grayed_out, starty); } - *starty -= UI_UNIT_Y; - - if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_draw_hierarchy_lines_recursive(pos, - space_outliner, - &te->subtree, - startx + UI_UNIT_X, - col, - draw_children_grayed_out, - starty); - } - } - - if (draw_grayed_out) { - immUniformColor3ubvAlpha(col, grayed_alpha); - } - else { - immUniformColor4ubv(col); - } - - /* Vertical line. */ - te = te_vertical_line_last; - if ((te != NULL) && (te->parent || lb->first != lb->last)) { - immRecti(pos, startx, y1 + UI_UNIT_Y, startx + U.pixelsize, y2); - } + if (draw_hierarchy_line) { + if (color_tag != COLLECTION_COLOR_NONE) { + immUniformColor4ubv(btheme->collection_color[color_tag].color); + } + else { + immUniformColor4ubv(col); + } - /* Children that are not in the collection are always in the end of the subtree. - * This way we can draw their own dashed vertical lines. */ - te = te_vertical_line_last_dashed; - if ((te != NULL) && (te->parent || lb->first != lb->last)) { - const int steps_num = ((y1_dashed + UI_UNIT_Y) - y2_dashed) / dash.step_len; - int start = y1_dashed + UI_UNIT_Y; - for (int i = 0; i < steps_num; i++) { - immRecti(pos, startx, start, startx + U.pixelsize, start - dash.step_len + dash.gap_len); - start -= dash.step_len; + outliner_draw_hierarchy_line(pos, startx, y, *starty, is_object_line); } } } @@ -3424,10 +3265,16 @@ static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner, int *starty) { GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uchar col[4]; - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform1f("dash_width", 8.0f); UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col); col[3] = 255; @@ -3641,8 +3488,8 @@ static void outliner_draw_tree(bContext *C, GPU_scissor(0, 0, mask_x, region->winy); } - /* Gray hierarchy lines. */ - starty = (int)region->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; + /* Draw hierarhcy lines for collections and object children. */ + starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET; startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2; outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty); |