From f4379cbc82cfe915e97a8e879567b820a10198f4 Mon Sep 17 00:00:00 2001 From: reduz Date: Sun, 4 Jul 2021 00:13:28 -0300 Subject: [PATCH] Clean up Tree Fixes some problems introduced by #49917 * Tree used minimum size as a stretch ratio, so it forced a minimum size of 1. * Minimum size redone, stretch ratio moved to a separate setting * Fitting to contents was enforced, this is more intuitive, but in many situations this is undesired. * Added a clip content option for situations where fit to contents does not apply. * Icon would scroll with the item, making it invislbe if the item is too long. * Made icon always appear to the right (or left if RTL is enabled) of the visible item space. --- doc/classes/Tree.xml | 44 +++++ editor/action_map_editor.cpp | 1 + editor/debugger/editor_network_profiler.cpp | 5 + editor/debugger/editor_profiler.cpp | 9 +- editor/debugger/editor_visual_profiler.cpp | 3 + editor/debugger/script_editor_debugger.cpp | 2 + editor/dependency_editor.cpp | 8 +- editor/editor_autoload_settings.cpp | 8 +- editor/editor_help_search.cpp | 2 + editor/editor_plugin_settings.cpp | 5 + editor/localization_editor.cpp | 2 + .../animation_player_editor_plugin.cpp | 6 +- .../resource_preloader_editor_plugin.cpp | 6 +- editor/plugins/theme_editor_plugin.cpp | 3 + scene/gui/tree.cpp | 150 ++++++++++++++---- scene/gui/tree.h | 15 +- 16 files changed, 225 insertions(+), 44 deletions(-) diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index be770e6e035..b20c6f334f1 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -96,6 +96,14 @@ Returns the column index at [code]position[/code], or -1 if no item is there. + + + + + + + + @@ -264,6 +272,22 @@ To tell whether a column of an item is selected, use [method TreeItem.is_selected]. + + + + + + + + + + + + + + + + @@ -272,6 +296,16 @@ + + + + + + + + + + @@ -294,6 +328,16 @@ If [code]true[/code], the column will have the "Expand" flag of [Control]. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio]. + + + + + + + + + + diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index fe1401bdf94..7ed603410d4 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -1123,6 +1123,7 @@ ActionMapEditor::ActionMapEditor() { action_tree->set_hide_root(true); action_tree->set_column_titles_visible(true); action_tree->set_column_title(0, TTR("Action")); + action_tree->set_column_clip_content(0, true); action_tree->set_column_title(1, TTR("Deadzone")); action_tree->set_column_expand(1, false); action_tree->set_column_custom_minimum_width(1, 80 * EDSCALE); diff --git a/editor/debugger/editor_network_profiler.cpp b/editor/debugger/editor_network_profiler.cpp index af83baeff8c..1c781c4d989 100644 --- a/editor/debugger/editor_network_profiler.cpp +++ b/editor/debugger/editor_network_profiler.cpp @@ -178,18 +178,23 @@ EditorNetworkProfiler::EditorNetworkProfiler() { counters_display->set_column_titles_visible(true); counters_display->set_column_title(0, TTR("Node")); counters_display->set_column_expand(0, true); + counters_display->set_column_clip_content(0, true); counters_display->set_column_custom_minimum_width(0, 60 * EDSCALE); counters_display->set_column_title(1, TTR("Incoming RPC")); counters_display->set_column_expand(1, false); + counters_display->set_column_clip_content(1, true); counters_display->set_column_custom_minimum_width(1, 120 * EDSCALE); counters_display->set_column_title(2, TTR("Incoming RSET")); counters_display->set_column_expand(2, false); + counters_display->set_column_clip_content(2, true); counters_display->set_column_custom_minimum_width(2, 120 * EDSCALE); counters_display->set_column_title(3, TTR("Outgoing RPC")); counters_display->set_column_expand(3, false); + counters_display->set_column_clip_content(3, true); counters_display->set_column_custom_minimum_width(3, 120 * EDSCALE); counters_display->set_column_title(4, TTR("Outgoing RSET")); counters_display->set_column_expand(4, false); + counters_display->set_column_clip_content(4, true); counters_display->set_column_custom_minimum_width(4, 120 * EDSCALE); add_child(counters_display); diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index ba84040b0ce..5f4d1b6f36f 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -631,13 +631,16 @@ EditorProfiler::EditorProfiler() { variables->set_column_titles_visible(true); variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); - variables->set_column_custom_minimum_width(0, 60 * EDSCALE); + variables->set_column_clip_content(0, true); + variables->set_column_expand_ratio(0, 60); variables->set_column_title(1, TTR("Time")); variables->set_column_expand(1, false); - variables->set_column_custom_minimum_width(1, 100 * EDSCALE); + variables->set_column_clip_content(1, true); + variables->set_column_expand_ratio(1, 100); variables->set_column_title(2, TTR("Calls")); variables->set_column_expand(2, false); - variables->set_column_custom_minimum_width(2, 60 * EDSCALE); + variables->set_column_clip_content(2, true); + variables->set_column_expand_ratio(2, 60); variables->connect("item_edited", callable_mp(this, &EditorProfiler::_item_edited)); graph = memnew(TextureRect); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 171d0574e0d..a0e8a3bd35a 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -773,12 +773,15 @@ EditorVisualProfiler::EditorVisualProfiler() { variables->set_column_titles_visible(true); variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); + variables->set_column_clip_content(0, true); variables->set_column_custom_minimum_width(0, 60); variables->set_column_title(1, TTR("CPU")); variables->set_column_expand(1, false); + variables->set_column_clip_content(1, true); variables->set_column_custom_minimum_width(1, 60 * EDSCALE); variables->set_column_title(2, TTR("GPU")); variables->set_column_expand(2, false); + variables->set_column_clip_content(2, true); variables->set_column_custom_minimum_width(2, 60 * EDSCALE); variables->connect("cell_selected", callable_mp(this, &EditorVisualProfiler::_item_selected)); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 0d3fd8c7f62..b877ab030f4 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1644,8 +1644,10 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { error_tree->set_column_expand(0, false); error_tree->set_column_custom_minimum_width(0, 140); + error_tree->set_column_clip_content(0, true); error_tree->set_column_expand(1, true); + error_tree->set_column_clip_content(1, true); error_tree->set_select_mode(Tree::SELECT_ROW); error_tree->set_hide_root(true); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 74a8ad90778..ef571e5c7a7 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -226,7 +226,11 @@ DependencyEditor::DependencyEditor() { tree->set_columns(2); tree->set_column_titles_visible(true); tree->set_column_title(0, TTR("Resource")); + tree->set_column_clip_content(0, true); + tree->set_column_expand_ratio(0, 2); tree->set_column_title(1, TTR("Path")); + tree->set_column_clip_content(1, true); + tree->set_column_expand_ratio(1, 1); tree->set_hide_root(true); tree->connect("button_pressed", callable_mp(this, &DependencyEditor::_load_pressed)); @@ -769,9 +773,11 @@ OrphanResourcesDialog::OrphanResourcesDialog() { files = memnew(Tree); files->set_columns(2); files->set_column_titles_visible(true); - files->set_column_custom_minimum_width(1, 100); + files->set_column_custom_minimum_width(1, 100 * EDSCALE); files->set_column_expand(0, true); + files->set_column_clip_content(0, true); files->set_column_expand(1, false); + files->set_column_clip_content(1, true); files->set_column_title(0, TTR("Resource")); files->set_column_title(1, TTR("Owns")); files->set_hide_root(true); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 306a88047a3..12ae55fbc1a 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -882,19 +882,17 @@ EditorAutoloadSettings::EditorAutoloadSettings() { tree->set_column_title(0, TTR("Name")); tree->set_column_expand(0, true); - tree->set_column_custom_minimum_width(0, 100 * EDSCALE); + tree->set_column_expand_ratio(0, 1); tree->set_column_title(1, TTR("Path")); tree->set_column_expand(1, true); - tree->set_column_custom_minimum_width(1, 100 * EDSCALE); + tree->set_column_clip_content(1, true); + tree->set_column_expand_ratio(1, 2); tree->set_column_title(2, TTR("Global Variable")); tree->set_column_expand(2, false); - // Reserve enough space for translations of "Global Variable" which may be longer. - tree->set_column_custom_minimum_width(2, 150 * EDSCALE); tree->set_column_expand(3, false); - tree->set_column_custom_minimum_width(3, 120 * EDSCALE); tree->connect("cell_selected", callable_mp(this, &EditorAutoloadSettings::_autoload_selected)); tree->connect("item_edited", callable_mp(this, &EditorAutoloadSettings::_autoload_edited)); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 57ddc64e957..a9bbb92079b 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -237,9 +237,11 @@ EditorHelpSearch::EditorHelpSearch() { results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); results_tree->set_columns(2); results_tree->set_column_title(0, TTR("Name")); + results_tree->set_column_clip_content(0, true); results_tree->set_column_title(1, TTR("Member Type")); results_tree->set_column_expand(1, false); results_tree->set_column_custom_minimum_width(1, 150 * EDSCALE); + results_tree->set_column_clip_content(1, true); results_tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE); results_tree->set_hide_root(true); results_tree->set_select_mode(Tree::SELECT_ROW); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 62fbad7bcf3..b4e5a58c216 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -212,10 +212,15 @@ EditorPluginSettings::EditorPluginSettings() { plugin_list->set_column_title(3, TTR("Status:")); plugin_list->set_column_title(4, TTR("Edit:")); plugin_list->set_column_expand(0, true); + plugin_list->set_column_clip_content(0, true); plugin_list->set_column_expand(1, false); + plugin_list->set_column_clip_content(1, true); plugin_list->set_column_expand(2, false); + plugin_list->set_column_clip_content(2, true); plugin_list->set_column_expand(3, false); + plugin_list->set_column_clip_content(3, true); plugin_list->set_column_expand(4, false); + plugin_list->set_column_clip_content(4, true); plugin_list->set_column_custom_minimum_width(1, 100 * EDSCALE); plugin_list->set_column_custom_minimum_width(2, 250 * EDSCALE); plugin_list->set_column_custom_minimum_width(3, 80 * EDSCALE); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 91a15f1131e..208d4437d34 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -728,7 +728,9 @@ LocalizationEditor::LocalizationEditor() { translation_remap_options->set_column_title(1, TTR("Locale")); translation_remap_options->set_column_titles_visible(true); translation_remap_options->set_column_expand(0, true); + translation_remap_options->set_column_clip_content(0, true); translation_remap_options->set_column_expand(1, false); + translation_remap_options->set_column_clip_content(1, true); translation_remap_options->set_column_custom_minimum_width(1, 200); translation_remap_options->connect("item_edited", callable_mp(this, &LocalizationEditor::_translation_res_option_changed)); translation_remap_options->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_res_option_delete)); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 48d7cfdee20..2b92943f7ec 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -569,8 +569,10 @@ void AnimationPlayerEditor::_animation_blend() { blend_editor.dialog->popup_centered(Size2(400, 400) * EDSCALE); blend_editor.tree->set_hide_root(true); - blend_editor.tree->set_column_custom_minimum_width(0, 10); - blend_editor.tree->set_column_custom_minimum_width(1, 3); + blend_editor.tree->set_column_expand_ratio(0, 10); + blend_editor.tree->set_column_clip_content(0, true); + blend_editor.tree->set_column_expand_ratio(1, 3); + blend_editor.tree->set_column_clip_content(1, true); List anims; player->get_animation_list(&anims); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index a7c11f8521a..488aa8c8619 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -367,8 +367,10 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { tree = memnew(Tree); tree->connect("button_pressed", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed)); tree->set_columns(2); - tree->set_column_custom_minimum_width(0, 2); - tree->set_column_custom_minimum_width(1, 3); + tree->set_column_expand_ratio(0, 2); + tree->set_column_clip_content(0, true); + tree->set_column_expand_ratio(1, 3); + tree->set_column_clip_content(1, true); tree->set_column_expand(0, true); tree->set_column_expand(1, true); tree->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 99d7267eac7..be1aeb309fb 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -930,11 +930,14 @@ ThemeItemImportTree::ThemeItemImportTree() { import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import")); import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data")); import_items_tree->set_column_expand(0, true); + import_items_tree->set_column_clip_content(0, true); import_items_tree->set_column_expand(IMPORT_ITEM, false); import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false); import_items_tree->set_column_custom_minimum_width(0, 160 * EDSCALE); import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM, 80 * EDSCALE); import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM_DATA, 80 * EDSCALE); + import_items_tree->set_column_clip_content(1, true); + import_items_tree->set_column_clip_content(2, true); ScrollContainer *import_bulk_sc = memnew(ScrollContainer); import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index aac15cd9a5f..fd9e87604f6 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -975,6 +975,9 @@ Size2 TreeItem::get_minimum_size(int p_column) { } // Icon. + if (cell.mode == CELL_MODE_CHECK) { + size.width += tree->cache.checked->get_width() + tree->cache.hseparation; + } if (cell.icon.is_valid()) { Size2i icon_size = cell.get_icon_size(); if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { @@ -1249,6 +1252,9 @@ void Tree::update_cache() { cache.item_margin = get_theme_constant("item_margin"); cache.button_margin = get_theme_constant("button_margin"); + cache.font_outline_color = get_theme_color("font_outline_color"); + cache.font_outline_size = get_theme_constant("outline_size"); + 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"); @@ -1510,7 +1516,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int htotal = 0; int label_h = compute_item_height(p_item); - bool rtl = is_layout_rtl(); + bool rtl = cache.rtl; /* Calculate height of the label part */ label_h += cache.vseparation; @@ -1556,6 +1562,20 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } + if (!rtl && p_item->cells[i].buttons.size()) { + int button_w = 0; + for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { + Ref b = p_item->cells[i].buttons[j].texture; + button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + } + + int total_ofs = ofs - cache.offset.x; + + if (total_ofs + w > p_draw_size.width) { + w = MAX(button_w, p_draw_size.width - total_ofs); + } + } + int bw = 0; for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { Ref b = p_item->cells[i].buttons[j].texture; @@ -1680,8 +1700,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color"); - Color font_outline_color = get_theme_color("font_outline_color"); - int outline_size = get_theme_constant("outline_size"); + Color font_outline_color = cache.font_outline_color; + int outline_size = cache.font_outline_size; Color icon_col = p_item->cells[i].icon_color; if (p_item->cells[i].dirty) { @@ -2139,9 +2159,16 @@ void Tree::_range_click_timeout() { Ref mb; mb.instantiate(); + int x_limit = get_size().width - cache.bg->get_minimum_size().width; + if (h_scroll->is_visible()) { + x_limit -= h_scroll->get_minimum_size().width; + } + + cache.rtl = is_layout_rtl(); + propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case) blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, false, root, MOUSE_BUTTON_LEFT, mb); + propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, false, root, MOUSE_BUTTON_LEFT, mb); blocked--; if (range_click_timer->is_one_shot()) { @@ -2164,7 +2191,7 @@ void Tree::_range_click_timeout() { } } -int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref &p_mod) { +int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, int p_button, const Ref &p_mod) { int item_h = compute_item_height(p_item) + cache.vseparation; bool skip = (p_item == root && hide_root); @@ -2189,6 +2216,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool int col = -1; int col_ofs = 0; int col_width = 0; + + int limit_w = x_limit; + for (int i = 0; i < columns.size(); i++) { col_width = get_column_width(i); @@ -2204,6 +2234,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool if (x > col_width) { col_ofs += col_width; x -= col_width; + limit_w -= col_width; continue; } @@ -2217,10 +2248,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool int margin = x_ofs + cache.item_margin; //-cache.hseparation; //int lm = cache.bg->get_margin(SIDE_LEFT); col_width -= margin; + limit_w -= margin; col_ofs += margin; x -= margin; } else { col_width -= cache.hseparation; + limit_w -= cache.hseparation; x -= cache.hseparation; } @@ -2234,6 +2267,16 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool bool already_selected = c.selected; bool already_cursor = (p_item == selected_item) && col == selected_col; + if (!cache.rtl && p_item->cells[col].buttons.size()) { + int button_w = 0; + for (int j = p_item->cells[col].buttons.size() - 1; j >= 0; j--) { + Ref b = p_item->cells[col].buttons[j].texture; + button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + } + + col_width = MAX(button_w, MIN(limit_w, col_width)); + } + for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref b = c.buttons[j].texture; int w = b->get_size().width + cache.button_pressed->get_minimum_size().width; @@ -2255,6 +2298,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool //emit_signal("button_pressed"); return -1; } + col_width -= w + cache.button_margin; } @@ -2465,7 +2509,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool TreeItem *c = p_item->first_child; while (c) { - int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod); + int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, x_limit, p_double_click, c, p_button, p_mod); if (child_h < 0) { return -1; // break, stop propagating, no need to anymore @@ -3143,8 +3187,14 @@ void Tree::_gui_input(Ref p_event) { pressing_for_editor = false; propagate_mouse_activated = false; + int x_limit = get_size().width - cache.bg->get_minimum_size().width; + if (h_scroll->is_visible()) { + x_limit -= h_scroll->get_minimum_size().width; + } + + cache.rtl = is_layout_rtl(); blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, b->is_double_click(), root, b->get_button_index(), b); + propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, b->is_double_click(), root, b->get_button_index(), b); blocked--; if (pressing_for_editor) { @@ -3496,6 +3546,9 @@ void Tree::_notification(int p_what) { Point2 draw_ofs; draw_ofs += bg->get_offset(); Size2 draw_size = get_size() - bg->get_minimum_size(); + if (h_scroll->is_visible()) { + draw_size.width -= h_scroll->get_minimum_size().width; + } bg->draw(ci, Rect2(Point2(), get_size())); @@ -3504,6 +3557,8 @@ void Tree::_notification(int p_what) { draw_ofs.y += tbh; draw_size.y -= tbh; + cache.rtl = is_layout_rtl(); + if (root && get_size().x > 0 && get_size().y > 0) { draw_item(Point2(), draw_ofs, draw_size, root); } @@ -3515,7 +3570,7 @@ void Tree::_notification(int p_what) { Ref sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); Ref f = cache.tb_font; Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh); - if (is_layout_rtl()) { + if (cache.rtl) { tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x; } sb->draw(ci, tbrect); @@ -3761,6 +3816,36 @@ void Tree::set_column_expand(int p_column, bool p_expand) { update(); } +void Tree::set_column_expand_ratio(int p_column, int p_ratio) { + ERR_FAIL_INDEX(p_column, columns.size()); + columns.write[p_column].expand_ratio = p_ratio; + update(); +} + +void Tree::set_column_clip_content(int p_column, bool p_fit) { + ERR_FAIL_INDEX(p_column, columns.size()); + + columns.write[p_column].clip_content = p_fit; + update(); +} + +bool Tree::is_column_expanding(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), false); + + return columns[p_column].expand; +} +int Tree::get_column_expand_ratio(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), 1); + + return columns[p_column].expand_ratio; +} + +bool Tree::is_column_clipping_content(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), false); + + return columns[p_column].clip_content; +} + TreeItem *Tree::get_selected() const { return selected_item; } @@ -3820,11 +3905,14 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) { int Tree::get_column_minimum_width(int p_column) const { ERR_FAIL_INDEX_V(p_column, columns.size(), -1); - if (columns[p_column].custom_min_width != 0) { - return columns[p_column].custom_min_width; - } else { + int min_width = columns[p_column].custom_min_width; + + if (show_column_titles) { + min_width = MAX(cache.font->get_string_size(columns[p_column].title).width, min_width); + } + + if (!columns[p_column].clip_content) { int depth = 0; - int min_width = 0; TreeItem *next; for (TreeItem *item = get_root(); item; item = next) { next = item->get_next_visible(); @@ -3848,13 +3936,16 @@ int Tree::get_column_minimum_width(int p_column) const { } min_width = MAX(min_width, item_size.width); } - return min_width; } + + return min_width; } int Tree::get_column_width(int p_column) const { ERR_FAIL_INDEX_V(p_column, columns.size(), -1); + int column_width = get_column_minimum_width(p_column); + if (columns[p_column].expand) { int expand_area = get_size().width; @@ -3868,31 +3959,24 @@ int Tree::get_column_width(int p_column) const { expand_area -= v_scroll->get_combined_minimum_size().width; } - int expanding_columns = 0; int expanding_total = 0; for (int i = 0; i < columns.size(); i++) { - if (!columns[i].expand) { - expand_area -= get_column_minimum_width(i); - } else { - expanding_total += get_column_minimum_width(i); - expanding_columns++; + expand_area -= get_column_minimum_width(i); + if (columns[i].expand) { + expanding_total += columns[i].expand_ratio; } } - if (expand_area < expanding_total) { - return get_column_minimum_width(p_column); + if (expand_area >= expanding_total && expanding_total > 0) { + column_width += expand_area * columns[p_column].expand_ratio / expanding_total; } - - ERR_FAIL_COND_V(expanding_columns == 0, -1); // shouldn't happen - if (expanding_total == 0) { - return 0; - } else { - return expand_area * get_column_minimum_width(p_column) / expanding_total; - } - } else { - return get_column_minimum_width(p_column); } + + if (p_column < columns.size() - 1) { + column_width += cache.hseparation; + } + return column_width; } void Tree::propagate_set_columns(TreeItem *p_item) { @@ -4549,6 +4633,12 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width); ClassDB::bind_method(D_METHOD("set_column_expand", "column", "expand"), &Tree::set_column_expand); + ClassDB::bind_method(D_METHOD("set_column_expand_ratio", "column", "ratio"), &Tree::set_column_expand_ratio); + ClassDB::bind_method(D_METHOD("set_column_clip_content", "column", "enable"), &Tree::set_column_clip_content); + ClassDB::bind_method(D_METHOD("is_column_expanding", "column"), &Tree::is_column_expanding); + ClassDB::bind_method(D_METHOD("is_column_clipping_content", "column"), &Tree::is_column_clipping_content); + ClassDB::bind_method(D_METHOD("get_column_expand_ratio", "column"), &Tree::get_column_expand_ratio); + ClassDB::bind_method(D_METHOD("get_column_width", "column"), &Tree::get_column_width); ClassDB::bind_method(D_METHOD("set_hide_root", "enable"), &Tree::set_hide_root); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index fd5fcd78380..10e66423033 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -411,7 +411,9 @@ private: struct ColumnInfo { int custom_min_width = 0; + int expand_ratio = 1; bool expand = true; + bool clip_content = false; String title; Ref text_buf; Dictionary opentype_features; @@ -450,7 +452,7 @@ private: void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color); int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false); - int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref &p_mod); + int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, int p_button, const Ref &p_mod); void _text_editor_submit(String p_text); void _text_editor_modal_close(); void value_editor_changed(double p_value); @@ -504,6 +506,7 @@ private: Color parent_hl_line_color; Color children_hl_line_color; Color custom_button_font_highlight; + Color font_outline_color; int hseparation = 0; int vseparation = 0; @@ -518,6 +521,7 @@ private: int draw_guides = 0; int scroll_border = 0; int scroll_speed = 0; + int font_outline_size = 0; enum ClickType { CLICK_NONE, @@ -540,6 +544,8 @@ private: Point2i text_editor_position; + bool rtl = false; + } cache; int _get_title_button_height() const; @@ -547,6 +553,7 @@ private: void _scroll_moved(float p_value); HScrollBar *h_scroll; VScrollBar *v_scroll; + bool h_scroll_enabled = true; bool v_scroll_enabled = true; @@ -632,8 +639,14 @@ public: void set_column_custom_minimum_width(int p_column, int p_min_width); void set_column_expand(int p_column, bool p_expand); + void set_column_expand_ratio(int p_column, int p_ratio); + void set_column_clip_content(int p_column, bool p_fit); int get_column_minimum_width(int p_column) const; int get_column_width(int p_column) const; + int get_column_expand_ratio(int p_column) const; + + bool is_column_expanding(int p_column) const; + bool is_column_clipping_content(int p_column) const; void set_hide_root(bool p_enabled); bool is_root_hidden() const;