From c78e9c3fbd828458935855a717db67c2794fcb16 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Thu, 18 Apr 2024 15:23:31 +0800 Subject: [PATCH] Fix TreeItem button handling - Fix incorrect tooltip and `get_button_id_at_position()` when column title is visible and when RTL layout is used - Take `button_margin`, `h_separation`, and `item_margin` into account --- scene/gui/tree.cpp | 181 +++++++++++++++++++++++++-------------------- scene/gui/tree.h | 2 + 2 files changed, 104 insertions(+), 79 deletions(-) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 9a2ba23ce886..0c48fac29fbe 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -35,8 +35,6 @@ #include "core/math/math_funcs.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/string/print_string.h" -#include "core/string/translation.h" #include "scene/gui/box_container.h" #include "scene/gui/text_edit.h" #include "scene/main/window.h" @@ -5267,6 +5265,86 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_ return nullptr; } +// When on a button, r_index is valid. +// When on an item, both r_item and r_column are valid. +// Otherwise, all output arguments are invalid. +void Tree::_find_button_at_pos(const Point2 &p_pos, TreeItem *&r_item, int &r_column, int &r_index) const { + r_item = nullptr; + r_column = -1; + r_index = -1; + + if (!root) { + return; + } + + Point2 pos = p_pos - theme_cache.panel_style->get_offset(); + pos.y -= _get_title_button_height(); + if (pos.y < 0) { + return; + } + + if (cache.rtl) { + pos.x = get_size().width - pos.x; + } + pos += theme_cache.offset; // Scrolling. + + int col, h, section; + TreeItem *it = _find_item_at_pos(root, pos, col, h, section); + if (!it) { + return; + } + + r_item = it; + r_column = col; + + const TreeItem::Cell &c = it->cells[col]; + if (c.buttons.is_empty()) { + return; + } + + int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width + theme_cache.offset.x; + if (v_scroll->is_visible_in_tree()) { + x_limit -= v_scroll->get_minimum_size().width; + } + + for (int i = 0; i < col; i++) { + const int col_w = get_column_width(i) + theme_cache.h_separation; + pos.x -= col_w; + x_limit -= col_w; + } + + int x_check; + if (cache.rtl) { + x_check = get_column_width(col); + } else { + // Right edge of the buttons area, relative to the start of the column. + int buttons_area_min = 0; + if (col == 0) { + // Content of column 0 should take indentation into account. + for (TreeItem *current = it; current && (current != root || !hide_root); current = current->parent) { + buttons_area_min += theme_cache.item_margin; + } + } + for (int i = c.buttons.size() - 1; i >= 0; i--) { + Ref b = c.buttons[i].texture; + buttons_area_min += b->get_size().width + theme_cache.button_pressed->get_minimum_size().width + theme_cache.button_margin; + } + + x_check = MAX(buttons_area_min, MIN(get_column_width(col), x_limit)); + } + + for (int i = c.buttons.size() - 1; i >= 0; i--) { + Ref b = c.buttons[i].texture; + Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); + if (pos.x > x_check - size.width) { + x_limit -= theme_cache.item_margin; + r_index = i; + return; + } + x_check -= size.width + theme_cache.button_margin; + } +} + int Tree::get_column_at_position(const Point2 &p_pos) const { if (root) { Point2 pos = p_pos; @@ -5358,92 +5436,37 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const { } int Tree::get_button_id_at_position(const Point2 &p_pos) const { - if (root) { - Point2 pos = p_pos; - pos -= theme_cache.panel_style->get_offset(); - pos.y -= _get_title_button_height(); - if (pos.y < 0) { - return -1; - } - - if (h_scroll->is_visible_in_tree()) { - pos.x += h_scroll->get_value(); - } - if (v_scroll->is_visible_in_tree()) { - pos.y += v_scroll->get_value(); - } - - int col, h, section; - TreeItem *it = _find_item_at_pos(root, pos, col, h, section); + TreeItem *it; + int col, index; + _find_button_at_pos(p_pos, it, col, index); - if (it) { - const TreeItem::Cell &c = it->cells[col]; - int col_width = get_column_width(col); - - for (int i = 0; i < col; i++) { - pos.x -= get_column_width(i); - } - - for (int j = c.buttons.size() - 1; j >= 0; j--) { - Ref b = c.buttons[j].texture; - Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); - if (pos.x > col_width - size.width) { - return c.buttons[j].id; - } - col_width -= size.width; - } - } + if (index == -1) { + return -1; } - - return -1; + return it->cells[col].buttons[index].id; } String Tree::get_tooltip(const Point2 &p_pos) const { - if (root) { - Point2 pos = p_pos; - pos -= theme_cache.panel_style->get_offset(); - pos.y -= _get_title_button_height(); - if (pos.y < 0) { - return Control::get_tooltip(p_pos); - } - - if (h_scroll->is_visible_in_tree()) { - pos.x += h_scroll->get_value(); - } - if (v_scroll->is_visible_in_tree()) { - pos.y += v_scroll->get_value(); - } + Point2 pos = p_pos - theme_cache.panel_style->get_offset(); + pos.y -= _get_title_button_height(); + if (pos.y < 0) { + return Control::get_tooltip(p_pos); + } - int col, h, section; - TreeItem *it = _find_item_at_pos(root, pos, col, h, section); + TreeItem *it; + int col, index; + _find_button_at_pos(p_pos, it, col, index); - if (it) { - const TreeItem::Cell &c = it->cells[col]; - int col_width = get_column_width(col); - - for (int i = 0; i < col; i++) { - pos.x -= get_column_width(i); - } + if (index != -1) { + return it->cells[col].buttons[index].tooltip; + } - for (int j = c.buttons.size() - 1; j >= 0; j--) { - Ref b = c.buttons[j].texture; - Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); - if (pos.x > col_width - size.width) { - String tooltip = c.buttons[j].tooltip; - if (!tooltip.is_empty()) { - return tooltip; - } - } - col_width -= size.width; - } - String ret; - if (it->get_tooltip_text(col) == "") { - ret = it->get_text(col); - } else { - ret = it->get_tooltip_text(col); - } - return ret; + if (it) { + const String item_tooltip = it->get_tooltip_text(col); + if (item_tooltip.is_empty()) { + return it->get_text(col); } + return item_tooltip; } return Control::get_tooltip(p_pos); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index c7c266a2e73f..311055a2f8b9 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -645,6 +645,8 @@ class Tree : public Control { TreeItem *_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int §ion) const; + void _find_button_at_pos(const Point2 &p_pos, TreeItem *&r_item, int &r_column, int &r_index) const; + /* float drag_speed; float drag_accum;