Add highlight to the relationship lines of selected Tree items

This commit is contained in:
Yuri Sizov 2021-05-02 18:34:29 +03:00
parent f164c00a94
commit 9c92e9d849
5 changed files with 134 additions and 17 deletions

View File

@ -533,6 +533,12 @@
<theme_item name="checked" type="Texture2D"> <theme_item name="checked" type="Texture2D">
The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode cell is checked. The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode cell is checked.
</theme_item> </theme_item>
<theme_item name="children_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
The [Color] of the relationship lines between the selected [TreeItem] and its children.
</theme_item>
<theme_item name="children_hl_line_width" type="int" default="1">
The width of the relationship lines between the selected [TreeItem] and its children.
</theme_item>
<theme_item name="cursor" type="StyleBox"> <theme_item name="cursor" type="StyleBox">
[StyleBox] used for the cursor, when the [Tree] is being focused. [StyleBox] used for the cursor, when the [Tree] is being focused.
</theme_item> </theme_item>
@ -587,8 +593,20 @@
<theme_item name="outline_size" type="int" default="0"> <theme_item name="outline_size" type="int" default="0">
The size of the text outline. The size of the text outline.
</theme_item> </theme_item>
<theme_item name="parent_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
The [Color] of the relationship lines between the selected [TreeItem] and its parents.
</theme_item>
<theme_item name="parent_hl_line_margin" type="int" default="0">
The space between the parent relationship lines for the selected [TreeItem] and the relationship lines to its siblings that are not selected.
</theme_item>
<theme_item name="parent_hl_line_width" type="int" default="1">
The width of the relationship lines between the selected [TreeItem] and its parents.
</theme_item>
<theme_item name="relationship_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )"> <theme_item name="relationship_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
[Color] of the relationship lines. The default [Color] of the relationship lines.
</theme_item>
<theme_item name="relationship_line_width" type="int" default="1">
The default width of the relationship lines.
</theme_item> </theme_item>
<theme_item name="scroll_border" type="int" default="4"> <theme_item name="scroll_border" type="int" default="4">
The maximum distance between the mouse cursor and the control's border to trigger border scrolling when dragging. The maximum distance between the mouse cursor and the control's border to trigger border scrolling when dragging.

View File

@ -799,8 +799,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tree_bg->set_border_color(dark_color_3); style_tree_bg->set_border_color(dark_color_3);
theme->set_stylebox("bg", "Tree", style_tree_bg); theme->set_stylebox("bg", "Tree", style_tree_bg);
const Color guide_color = mono_color * Color(1, 1, 1, 0.05);
Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity);
// Tree // Tree
theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons")); theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons"));
@ -817,19 +815,33 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "Tree", font_color); theme->set_color("font_color", "Tree", font_color);
theme->set_color("font_selected_color", "Tree", mono_color); theme->set_color("font_selected_color", "Tree", mono_color);
theme->set_color("title_button_color", "Tree", font_color); theme->set_color("title_button_color", "Tree", font_color);
theme->set_color("guide_color", "Tree", guide_color);
theme->set_color("relationship_line_color", "Tree", relationship_line_color);
theme->set_color("drop_position_color", "Tree", accent_color); theme->set_color("drop_position_color", "Tree", accent_color);
theme->set_constant("vseparation", "Tree", widget_default_margin.y - EDSCALE); theme->set_constant("vseparation", "Tree", widget_default_margin.y - EDSCALE);
theme->set_constant("hseparation", "Tree", 6 * EDSCALE); theme->set_constant("hseparation", "Tree", 6 * EDSCALE);
theme->set_constant("guide_width", "Tree", border_width); theme->set_constant("guide_width", "Tree", border_width);
theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE); theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE);
theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE); theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE);
theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01);
theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01);
theme->set_constant("scroll_border", "Tree", 40 * EDSCALE); theme->set_constant("scroll_border", "Tree", 40 * EDSCALE);
theme->set_constant("scroll_speed", "Tree", 12); theme->set_constant("scroll_speed", "Tree", 12);
const Color guide_color = mono_color * Color(1, 1, 1, 0.05);
Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity);
theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01);
theme->set_color("guide_color", "Tree", guide_color);
int relationship_line_width = 1;
Color parent_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.45, 0.0, 1.0));
Color children_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.25, 0.0, 1.0));
theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01);
theme->set_constant("relationship_line_width", "Tree", relationship_line_width);
theme->set_constant("parent_hl_line_width", "Tree", relationship_line_width * 2);
theme->set_constant("children_hl_line_width", "Tree", relationship_line_width);
theme->set_constant("parent_hl_line_margin", "Tree", relationship_line_width * 3);
theme->set_color("relationship_line_color", "Tree", relationship_line_color);
theme->set_color("parent_hl_line_color", "Tree", parent_line_color);
theme->set_color("children_hl_line_color", "Tree", children_line_color);
Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate(); Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate();
style_tree_btn->set_bg_color(highlight_color); style_tree_btn->set_bg_color(highlight_color);
style_tree_btn->set_border_width_all(0); style_tree_btn->set_border_width_all(0);

View File

@ -1184,15 +1184,23 @@ void Tree::update_cache() {
cache.font_color = get_theme_color("font_color"); cache.font_color = get_theme_color("font_color");
cache.font_selected_color = get_theme_color("font_selected_color"); cache.font_selected_color = get_theme_color("font_selected_color");
cache.guide_color = get_theme_color("guide_color");
cache.drop_position_color = get_theme_color("drop_position_color"); cache.drop_position_color = get_theme_color("drop_position_color");
cache.hseparation = get_theme_constant("hseparation"); cache.hseparation = get_theme_constant("hseparation");
cache.vseparation = get_theme_constant("vseparation"); cache.vseparation = get_theme_constant("vseparation");
cache.item_margin = get_theme_constant("item_margin"); cache.item_margin = get_theme_constant("item_margin");
cache.button_margin = get_theme_constant("button_margin"); cache.button_margin = get_theme_constant("button_margin");
cache.draw_guides = get_theme_constant("draw_guides"); cache.draw_guides = get_theme_constant("draw_guides");
cache.guide_color = get_theme_color("guide_color");
cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines"); cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines");
cache.relationship_line_width = get_theme_constant("relationship_line_width");
cache.parent_hl_line_width = get_theme_constant("parent_hl_line_width");
cache.children_hl_line_width = get_theme_constant("children_hl_line_width");
cache.parent_hl_line_margin = get_theme_constant("parent_hl_line_margin");
cache.relationship_line_color = get_theme_color("relationship_line_color"); cache.relationship_line_color = get_theme_color("relationship_line_color");
cache.parent_hl_line_color = get_theme_color("parent_hl_line_color");
cache.children_hl_line_color = get_theme_color("children_hl_line_color");
cache.scroll_border = get_theme_constant("scroll_border"); cache.scroll_border = get_theme_constant("scroll_border");
cache.scroll_speed = get_theme_constant("scroll_speed"); cache.scroll_speed = get_theme_constant("scroll_speed");
@ -1813,38 +1821,73 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
TreeItem *c = p_item->first_child; TreeItem *c = p_item->first_child;
int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
int prev_ofs = base_ofs;
int prev_hl_ofs = base_ofs;
while (c) { while (c) {
if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) {
int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + cache.item_margin;
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
if (c->get_first_child() != nullptr) { if (c->get_first_child() != nullptr) {
root_pos -= Point2i(cache.arrow->get_width(), 0); root_pos -= Point2i(cache.arrow->get_width(), 0);
} }
float line_width = 1.0; float line_width = cache.relationship_line_width;
float parent_line_width = cache.parent_hl_line_width;
float children_line_width = cache.children_hl_line_width;
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
line_width *= Math::round(EDSCALE); line_width *= Math::round(EDSCALE);
parent_line_width *= Math::round(EDSCALE);
children_line_width *= Math::round(EDSCALE);
#endif #endif
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
int more_prev_ofs = 0;
if (root_pos.y + line_width >= 0) { if (root_pos.y + line_width >= 0) {
if (rtl) { if (rtl) {
root_pos.x = get_size().width - root_pos.x; root_pos.x = get_size().width - root_pos.x;
parent_pos.x = get_size().width - parent_pos.x; parent_pos.x = get_size().width - parent_pos.x;
} }
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width); // Order of parts on this bend: the horizontal line first, then the vertical line.
if (_is_branch_selected(c)) {
// If this item or one of its children is selected, we draw the line using parent highlight style.
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width);
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
more_prev_ofs = cache.parent_hl_line_margin;
prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
} else if (p_item->is_selected(0)) {
// If parent item is selected (but this item is not), we draw the line using children highlight style.
// Siblings of the selected branch can be drawn with a slight offset (and also don't need a vertical line).
if (_is_sibling_branch_selected(c)) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
} else {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width);
}
} else {
// If nothing of the above is true, we draw the line using normal style.
// Siblings of the selected branch can be drawn with a slight offset (and also don't need a vertical line).
if (_is_sibling_branch_selected(c)) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width);
} else {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width);
}
}
} }
if (htotal < 0) { if (htotal < 0) {
return -1; return -1;
} }
prev_ofs = root_pos.y; prev_ofs = root_pos.y + more_prev_ofs;
} }
if (htotal >= 0) { if (htotal >= 0) {
@ -1853,10 +1896,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (child_h < 0) { if (child_h < 0) {
if (cache.draw_relationship_lines == 0) { if (cache.draw_relationship_lines == 0) {
return -1; // break, stop drawing, no need to anymore return -1; // break, stop drawing, no need to anymore
} else {
htotal = -1;
children_pos.y = cache.offset.y + p_draw_size.height;
} }
htotal = -1;
children_pos.y = cache.offset.y + p_draw_size.height;
} else { } else {
htotal += child_h; htotal += child_h;
children_pos.y += child_h; children_pos.y += child_h;
@ -1889,6 +1932,36 @@ int Tree::_count_selected_items(TreeItem *p_from) const {
return count; return count;
} }
bool Tree::_is_branch_selected(TreeItem *p_from) const {
for (int i = 0; i < columns.size(); i++) {
if (p_from->is_selected(i)) {
return true;
}
}
TreeItem *child_item = p_from->get_first_child();
while (child_item) {
if (_is_branch_selected(child_item)) {
return true;
}
child_item = child_item->get_next();
}
return false;
}
bool Tree::_is_sibling_branch_selected(TreeItem *p_from) const {
TreeItem *sibling_item = p_from->get_next();
while (sibling_item) {
if (_is_branch_selected(sibling_item)) {
return true;
}
sibling_item = sibling_item->get_next();
}
return false;
}
void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) { void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) {
TreeItem::Cell &selected_cell = p_selected->cells.write[p_col]; TreeItem::Cell &selected_cell = p_selected->cells.write[p_col];

View File

@ -494,6 +494,8 @@ private:
Color guide_color; Color guide_color;
Color drop_position_color; Color drop_position_color;
Color relationship_line_color; Color relationship_line_color;
Color parent_hl_line_color;
Color children_hl_line_color;
Color custom_button_font_highlight; Color custom_button_font_highlight;
int hseparation = 0; int hseparation = 0;
@ -502,6 +504,10 @@ private:
int button_margin = 0; int button_margin = 0;
Point2 offset; Point2 offset;
int draw_relationship_lines = 0; int draw_relationship_lines = 0;
int relationship_line_width = 0;
int parent_hl_line_width = 0;
int children_hl_line_width = 0;
int parent_hl_line_margin = 0;
int draw_guides = 0; int draw_guides = 0;
int scroll_border = 0; int scroll_border = 0;
int scroll_speed = 0; int scroll_speed = 0;
@ -574,6 +580,8 @@ private:
bool hide_folding = false; bool hide_folding = false;
int _count_selected_items(TreeItem *p_from) const; int _count_selected_items(TreeItem *p_from) const;
bool _is_branch_selected(TreeItem *p_from) const;
bool _is_sibling_branch_selected(TreeItem *p_from) const;
void _go_left(); void _go_left();
void _go_right(); void _go_right();
void _go_down(); void _go_down();

View File

@ -719,6 +719,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1)); theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1));
theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color); theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color);
theme->set_constant("hseparation", "Tree", 4 * scale); theme->set_constant("hseparation", "Tree", 4 * scale);
@ -726,6 +728,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("item_margin", "Tree", 12 * scale); theme->set_constant("item_margin", "Tree", 12 * scale);
theme->set_constant("button_margin", "Tree", 4 * scale); theme->set_constant("button_margin", "Tree", 4 * scale);
theme->set_constant("draw_relationship_lines", "Tree", 0); theme->set_constant("draw_relationship_lines", "Tree", 0);
theme->set_constant("relationship_line_width", "Tree", 1);
theme->set_constant("parent_hl_line_width", "Tree", 1);
theme->set_constant("children_hl_line_width", "Tree", 1);
theme->set_constant("parent_hl_line_margin", "Tree", 0);
theme->set_constant("draw_guides", "Tree", 1); theme->set_constant("draw_guides", "Tree", 1);
theme->set_constant("scroll_border", "Tree", 4); theme->set_constant("scroll_border", "Tree", 4);
theme->set_constant("scroll_speed", "Tree", 12); theme->set_constant("scroll_speed", "Tree", 12);