mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Merge pull request #88530 from davthedev/tree-hover-items
Add hover state to Tree items display
This commit is contained in:
commit
77da16ce69
@ -509,6 +509,12 @@
|
||||
<theme_item name="font_disabled_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
|
||||
Text [Color] for a [constant TreeItem.CELL_MODE_CHECK] mode cell when it's non-editable (see [method TreeItem.set_editable]).
|
||||
</theme_item>
|
||||
<theme_item name="font_hovered_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
|
||||
Text [Color] used when the item is hovered.
|
||||
</theme_item>
|
||||
<theme_item name="font_hovered_dimmed_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
|
||||
Text [Color] used when the item is hovered, while a button of the same item is hovered as the same time.
|
||||
</theme_item>
|
||||
<theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
|
||||
The tint of text outline of the item.
|
||||
</theme_item>
|
||||
@ -645,6 +651,9 @@
|
||||
<theme_item name="updown" data_type="icon" type="Texture2D">
|
||||
The updown arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode cell.
|
||||
</theme_item>
|
||||
<theme_item name="button_hover" data_type="style" type="StyleBox">
|
||||
[StyleBox] used when a button in the tree is hovered.
|
||||
</theme_item>
|
||||
<theme_item name="button_pressed" data_type="style" type="StyleBox">
|
||||
[StyleBox] used when a button in the tree is pressed.
|
||||
</theme_item>
|
||||
@ -666,6 +675,12 @@
|
||||
<theme_item name="focus" data_type="style" type="StyleBox">
|
||||
The focused style for the [Tree], drawn on top of everything.
|
||||
</theme_item>
|
||||
<theme_item name="hovered" data_type="style" type="StyleBox">
|
||||
[StyleBox] for the item being hovered.
|
||||
</theme_item>
|
||||
<theme_item name="hovered_dimmed" data_type="style" type="StyleBox">
|
||||
[StyleBox] for the item being hovered, while a button of the same item is hovered as the same time.
|
||||
</theme_item>
|
||||
<theme_item name="panel" data_type="style" type="StyleBox">
|
||||
The background style for the [Tree].
|
||||
</theme_item>
|
||||
|
@ -88,7 +88,7 @@ void ProjectListItemControl::_notification(int p_what) {
|
||||
draw_style_box(get_theme_stylebox(SNAME("selected"), SNAME("Tree")), Rect2(Point2(), get_size()));
|
||||
}
|
||||
if (is_hovering) {
|
||||
draw_style_box(get_theme_stylebox(SNAME("hover"), SNAME("Tree")), Rect2(Point2(), get_size()));
|
||||
draw_style_box(get_theme_stylebox(SNAME("hovered"), SNAME("Tree")), Rect2(Point2(), get_size()));
|
||||
}
|
||||
|
||||
draw_line(Point2(0, get_size().y + 1), Point2(get_size().x, get_size().y + 1), get_theme_color(SNAME("guide_color"), SNAME("Tree")));
|
||||
|
@ -945,6 +945,8 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
|
||||
|
||||
p_theme->set_color("custom_button_font_highlight", "Tree", p_config.font_hover_color);
|
||||
p_theme->set_color(SceneStringName(font_color), "Tree", p_config.font_color);
|
||||
p_theme->set_color("font_hovered_color", "Tree", p_config.mono_color);
|
||||
p_theme->set_color("font_hovered_dimmed_color", "Tree", p_config.font_color);
|
||||
p_theme->set_color("font_selected_color", "Tree", p_config.mono_color);
|
||||
p_theme->set_color("font_disabled_color", "Tree", p_config.font_disabled_color);
|
||||
p_theme->set_color("font_outline_color", "Tree", p_config.font_outline_color);
|
||||
@ -997,7 +999,13 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
|
||||
Ref<StyleBoxFlat> style_tree_hover = p_config.base_style->duplicate();
|
||||
style_tree_hover->set_bg_color(p_config.highlight_color * Color(1, 1, 1, 0.4));
|
||||
style_tree_hover->set_border_width_all(0);
|
||||
p_theme->set_stylebox("hover", "Tree", style_tree_hover);
|
||||
p_theme->set_stylebox("hovered", "Tree", style_tree_hover);
|
||||
p_theme->set_stylebox("button_hover", "Tree", style_tree_hover);
|
||||
|
||||
Ref<StyleBoxFlat> style_tree_hover_dimmed = p_config.base_style->duplicate();
|
||||
style_tree_hover_dimmed->set_bg_color(p_config.highlight_color * Color(1, 1, 1, 0.2));
|
||||
style_tree_hover_dimmed->set_border_width_all(0);
|
||||
p_theme->set_stylebox("hovered_dimmed", "Tree", style_tree_hover_dimmed);
|
||||
|
||||
p_theme->set_stylebox("selected_focus", "Tree", style_tree_focus);
|
||||
p_theme->set_stylebox("selected", "Tree", style_tree_selected);
|
||||
|
@ -2165,12 +2165,18 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
|
||||
int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.h_separation : theme_cache.item_margin);
|
||||
int skip2 = 0;
|
||||
|
||||
bool is_row_hovered = (!cache.hover_header_row && cache.hover_item == p_item);
|
||||
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (skip2) {
|
||||
skip2--;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_col_hovered = cache.hover_column == i;
|
||||
bool is_cell_hovered = is_row_hovered && is_col_hovered;
|
||||
bool is_cell_button_hovered = is_cell_hovered && cache.hover_button_index_in_column != -1;
|
||||
int item_width = get_column_width(i);
|
||||
|
||||
if (i == 0) {
|
||||
@ -2203,6 +2209,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
|
||||
int total_ofs = ofs - theme_cache.offset.x;
|
||||
|
||||
// If part of the column is beyond the right side of the control due to scrolling, clamp the label width
|
||||
// so that all buttons attached to the cell remain within view.
|
||||
if (total_ofs + item_width > p_draw_size.width) {
|
||||
item_width = MAX(buttons_width, p_draw_size.width - total_ofs);
|
||||
}
|
||||
@ -2247,17 +2255,42 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, theme_cache.guide_color, 1);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
if (p_item->cells[0].selected && select_mode == SELECT_ROW) {
|
||||
if (i == 0 && select_mode == SELECT_ROW) {
|
||||
if (p_item->cells[0].selected || is_row_hovered) {
|
||||
const Rect2 content_rect = _get_content_rect();
|
||||
Rect2i row_rect = Rect2i(Point2i(content_rect.position.x, item_rect.position.y), Size2i(content_rect.size.x, item_rect.size.y));
|
||||
if (rtl) {
|
||||
row_rect.position.x = get_size().width - row_rect.position.x - row_rect.size.x;
|
||||
}
|
||||
if (has_focus()) {
|
||||
theme_cache.selected_focus->draw(ci, row_rect);
|
||||
|
||||
if (p_item->cells[0].selected) {
|
||||
if (has_focus()) {
|
||||
theme_cache.selected_focus->draw(ci, row_rect);
|
||||
} else {
|
||||
theme_cache.selected->draw(ci, row_rect);
|
||||
}
|
||||
} else if (!drop_mode_flags) {
|
||||
if (is_cell_button_hovered) {
|
||||
theme_cache.hovered_dimmed->draw(ci, row_rect);
|
||||
} else {
|
||||
theme_cache.hovered->draw(ci, row_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (select_mode != SELECT_ROW) {
|
||||
Rect2i r = cell_rect;
|
||||
if (rtl) {
|
||||
r.position.x = get_size().width - r.position.x - r.size.x;
|
||||
}
|
||||
|
||||
// Cell hover.
|
||||
if (is_cell_hovered && !p_item->cells[i].selected && !drop_mode_flags) {
|
||||
if (is_cell_button_hovered) {
|
||||
theme_cache.hovered_dimmed->draw(ci, r);
|
||||
} else {
|
||||
theme_cache.selected->draw(ci, row_rect);
|
||||
theme_cache.hovered->draw(ci, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2335,7 +2368,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
if (p_item->cells[i].custom_color) {
|
||||
cell_color = p_item->cells[i].color;
|
||||
} else {
|
||||
cell_color = p_item->cells[i].selected ? theme_cache.font_selected_color : theme_cache.font_color;
|
||||
bool draw_as_hover = !drop_mode_flags && (select_mode == SELECT_ROW ? is_row_hovered : is_cell_hovered);
|
||||
bool draw_as_hover_dim = draw_as_hover && is_cell_button_hovered;
|
||||
cell_color = p_item->cells[i].selected ? theme_cache.font_selected_color : (draw_as_hover_dim ? theme_cache.font_hovered_dimmed_color : (draw_as_hover ? theme_cache.font_hovered_color : theme_cache.font_color));
|
||||
}
|
||||
|
||||
Color font_outline_color = theme_cache.font_outline_color;
|
||||
@ -2487,7 +2522,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
ir.size.width -= downarrow->get_width();
|
||||
|
||||
if (p_item->cells[i].custom_button) {
|
||||
if (cache.hover_item == p_item && cache.hover_cell == i) {
|
||||
if (cache.hover_item == p_item && cache.hover_column == i) {
|
||||
if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
|
||||
draw_style_box(theme_cache.custom_button_pressed, ir);
|
||||
} else {
|
||||
@ -2508,19 +2543,26 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
} break;
|
||||
}
|
||||
|
||||
// Draw the buttons inside the cell.
|
||||
for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) {
|
||||
Ref<Texture2D> button_texture = p_item->cells[i].buttons[j].texture;
|
||||
Size2 button_size = button_texture->get_size() + theme_cache.button_pressed->get_minimum_size();
|
||||
|
||||
Point2i button_ofs = Point2i(ofs + item_width_with_buttons - button_size.width, p_pos.y) - theme_cache.offset + p_draw_ofs;
|
||||
|
||||
if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled) {
|
||||
// Being pressed.
|
||||
bool should_draw_pressed = cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled;
|
||||
bool should_draw_hovered = !should_draw_pressed && !drop_mode_flags && cache.hover_item == p_item && cache.hover_column == i && cache.hover_button_index_in_column == j && !p_item->cells[i].buttons[j].disabled;
|
||||
|
||||
if (should_draw_pressed || should_draw_hovered) {
|
||||
Point2 od = button_ofs;
|
||||
if (rtl) {
|
||||
od.x = get_size().width - od.x - button_size.x;
|
||||
}
|
||||
theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
|
||||
if (should_draw_pressed) {
|
||||
theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
|
||||
} else {
|
||||
theme_cache.button_hover->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
|
||||
}
|
||||
}
|
||||
|
||||
button_ofs.y += (label_h - button_size.height) / 2;
|
||||
@ -2551,6 +2593,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the folding arrow.
|
||||
if (!p_item->disable_folding && !hide_folding && p_item->first_child && p_item->get_visible_child_count() != 0) { //has visible children, draw the guide box
|
||||
|
||||
Ref<Texture2D> arrow;
|
||||
@ -2966,6 +3009,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
|
||||
col_width = MAX(button_w, MIN(limit_w, col_width));
|
||||
}
|
||||
|
||||
// Cell button detection code.
|
||||
for (int j = c.buttons.size() - 1; j >= 0; j--) {
|
||||
Ref<Texture2D> b = c.buttons[j].texture;
|
||||
int w = b->get_size().width + theme_cache.button_pressed->get_minimum_size().width;
|
||||
@ -3485,7 +3529,11 @@ bool Tree::_scroll(bool p_horizontal, float p_pages) {
|
||||
double prev_value = scroll->get_value();
|
||||
scroll->set_value(scroll->get_value() + scroll->get_page() * p_pages);
|
||||
|
||||
return scroll->get_value() != prev_value;
|
||||
bool scroll_happened = scroll->get_value() != prev_value;
|
||||
if (scroll_happened) {
|
||||
_determine_hovered_item();
|
||||
}
|
||||
return scroll_happened;
|
||||
}
|
||||
|
||||
Rect2 Tree::_get_scrollbar_layout_rect() const {
|
||||
@ -3710,92 +3758,10 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid()) {
|
||||
Ref<StyleBox> bg = theme_cache.panel_style;
|
||||
hovered_pos = mm->get_position();
|
||||
_determine_hovered_item();
|
||||
|
||||
bool rtl = is_layout_rtl();
|
||||
|
||||
Point2 pos = mm->get_position();
|
||||
if (rtl) {
|
||||
pos.x = get_size().width - pos.x;
|
||||
}
|
||||
pos -= theme_cache.panel_style->get_offset();
|
||||
|
||||
Cache::ClickType old_hover = cache.hover_type;
|
||||
int old_index = cache.hover_index;
|
||||
|
||||
cache.hover_type = Cache::CLICK_NONE;
|
||||
cache.hover_index = 0;
|
||||
if (show_column_titles) {
|
||||
pos.y -= _get_title_button_height();
|
||||
if (pos.y < 0) {
|
||||
pos.x += theme_cache.offset.x;
|
||||
int len = 0;
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
len += get_column_width(i);
|
||||
if (pos.x < len) {
|
||||
cache.hover_type = Cache::CLICK_TITLE;
|
||||
cache.hover_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (root) {
|
||||
Point2 mpos = mm->get_position();
|
||||
if (rtl) {
|
||||
mpos.x = get_size().width - mpos.x;
|
||||
}
|
||||
mpos -= theme_cache.panel_style->get_offset();
|
||||
mpos.y -= _get_title_button_height();
|
||||
if (mpos.y >= 0) {
|
||||
if (h_scroll->is_visible_in_tree()) {
|
||||
mpos.x += h_scroll->get_value();
|
||||
}
|
||||
if (v_scroll->is_visible_in_tree()) {
|
||||
mpos.y += v_scroll->get_value();
|
||||
}
|
||||
|
||||
TreeItem *old_it = cache.hover_item;
|
||||
int old_col = cache.hover_cell;
|
||||
|
||||
int col, h, section;
|
||||
TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
|
||||
|
||||
if (drop_mode_flags) {
|
||||
if (it != drop_mode_over) {
|
||||
drop_mode_over = it;
|
||||
queue_redraw();
|
||||
}
|
||||
if (it && section != drop_mode_section) {
|
||||
drop_mode_section = section;
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
cache.hover_item = it;
|
||||
cache.hover_cell = col;
|
||||
|
||||
if (it != old_it || col != old_col) {
|
||||
if (old_it && old_col >= old_it->cells.size()) {
|
||||
// Columns may have changed since last redraw().
|
||||
queue_redraw();
|
||||
} else {
|
||||
// Only need to update if mouse enters/exits a button
|
||||
bool was_over_button = old_it && old_it->cells[old_col].custom_button;
|
||||
bool is_over_button = it && it->cells[col].custom_button;
|
||||
if (was_over_button || is_over_button) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update if mouse enters/exits columns
|
||||
if (cache.hover_type != old_hover || cache.hover_index != old_index) {
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
if (pressing_for_editor && popup_pressing_edited_item && (popup_pressing_edited_item->get_cell_mode(popup_pressing_edited_item_column) == TreeItem::CELL_MODE_RANGE)) {
|
||||
/* This needs to happen now, because the popup can be closed when pressing another item, and must remain the popup edited item until it actually closes */
|
||||
popup_edited_item = popup_pressing_edited_item;
|
||||
@ -4080,6 +4046,174 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
|
||||
}
|
||||
}
|
||||
|
||||
void Tree::_determine_hovered_item() {
|
||||
Ref<StyleBox> bg = theme_cache.panel_style;
|
||||
bool rtl = is_layout_rtl();
|
||||
|
||||
Point2 pos = hovered_pos;
|
||||
if (rtl) {
|
||||
pos.x = get_size().width - pos.x;
|
||||
}
|
||||
pos -= theme_cache.panel_style->get_offset();
|
||||
|
||||
bool old_header_row = cache.hover_header_row;
|
||||
int old_header_column = cache.hover_header_column;
|
||||
TreeItem *old_item = cache.hover_item;
|
||||
int old_column = cache.hover_column;
|
||||
int old_button_index_in_column = cache.hover_button_index_in_column;
|
||||
|
||||
// Determine hover on column headers.
|
||||
cache.hover_header_row = false;
|
||||
cache.hover_header_column = 0;
|
||||
if (show_column_titles && is_mouse_hovering) {
|
||||
pos.y -= _get_title_button_height();
|
||||
if (pos.y < 0) {
|
||||
pos.x += theme_cache.offset.x;
|
||||
int len = 0;
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
len += get_column_width(i);
|
||||
if (pos.x < len) {
|
||||
cache.hover_header_row = true;
|
||||
cache.hover_header_column = i;
|
||||
cache.hover_button_index_in_column = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine hover on rows and items.
|
||||
if (root && is_mouse_hovering) {
|
||||
Point2 mpos = hovered_pos;
|
||||
if (rtl) {
|
||||
mpos.x = get_size().width - mpos.x;
|
||||
}
|
||||
mpos -= theme_cache.panel_style->get_offset();
|
||||
mpos.y -= _get_title_button_height();
|
||||
if (mpos.y >= 0) {
|
||||
if (h_scroll->is_visible_in_tree()) {
|
||||
mpos.x += h_scroll->get_value();
|
||||
}
|
||||
if (v_scroll->is_visible_in_tree()) {
|
||||
mpos.y += v_scroll->get_value();
|
||||
}
|
||||
|
||||
int col, h, section;
|
||||
TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
|
||||
|
||||
// Find possible hovered button in cell.
|
||||
int col_button_index = -1;
|
||||
|
||||
Point2 cpos = mpos;
|
||||
|
||||
if (it) {
|
||||
const TreeItem::Cell &c = it->cells[col];
|
||||
int col_width = get_column_width(col);
|
||||
|
||||
// In the first column, tree nesting indent impacts the leftmost possible buttons position
|
||||
// and the clickable area of the folding arrow.
|
||||
int col_indent = 0;
|
||||
if (col == 0) {
|
||||
col_indent = _get_item_h_offset(it);
|
||||
}
|
||||
|
||||
// Compute total width of buttons block including spacings.
|
||||
int buttons_width = 0;
|
||||
for (int j = c.buttons.size() - 1; j >= 0; j--) {
|
||||
Ref<Texture2D> b = c.buttons[j].texture;
|
||||
Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
|
||||
buttons_width += size.width + theme_cache.button_margin;
|
||||
}
|
||||
|
||||
// Adjust when buttons are shifted left into view so that they remain visible even
|
||||
// if part of the cell is beyond the right border due to horizontal scrolling and
|
||||
// a long string in one of the items. This matches the drawing & click handling algorithms
|
||||
// that are based on recursion.
|
||||
int clamped_column_offset = 0;
|
||||
int col_left = 0;
|
||||
|
||||
for (int i = 0; i < col; i++) {
|
||||
int i_col_w = get_column_width(i);
|
||||
cpos.x -= i_col_w;
|
||||
col_left += i_col_w;
|
||||
}
|
||||
col_left -= theme_cache.offset.x;
|
||||
|
||||
// Compute buttons offset that makes them visible, in comparison to what would be their
|
||||
// natural position that would cut them off.
|
||||
if (!rtl) {
|
||||
const Rect2 content_rect = _get_content_rect();
|
||||
int cw = content_rect.size.width;
|
||||
int col_right = col_left + col_width;
|
||||
if (col_right > cw) {
|
||||
clamped_column_offset = col_right - cw - theme_cache.scrollbar_h_separation;
|
||||
int max_clamp_offset = col_width - col_indent - buttons_width;
|
||||
if (clamped_column_offset > max_clamp_offset) {
|
||||
clamped_column_offset = max_clamp_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
col_width -= clamped_column_offset;
|
||||
|
||||
// Find the actual button under coordinates.
|
||||
for (int j = c.buttons.size() - 1; j >= 0; j--) {
|
||||
Ref<Texture2D> b = c.buttons[j].texture;
|
||||
Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
|
||||
if (cpos.x > col_width - size.width && col_button_index == -1) {
|
||||
col_button_index = j;
|
||||
}
|
||||
col_width -= size.width + theme_cache.button_margin;
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_mode_flags) {
|
||||
if (it != drop_mode_over) {
|
||||
drop_mode_over = it;
|
||||
queue_redraw();
|
||||
}
|
||||
if (it && section != drop_mode_section) {
|
||||
drop_mode_section = section;
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
cache.hover_item = it;
|
||||
cache.hover_column = col;
|
||||
cache.hover_button_index_in_column = col_button_index;
|
||||
|
||||
if (it != old_item || col != old_column) {
|
||||
if (old_item && old_column >= old_item->cells.size()) {
|
||||
// Columns may have changed since last redraw().
|
||||
queue_redraw();
|
||||
} else {
|
||||
// Only need to update if mouse enters/exits a button.
|
||||
bool was_over_button = old_item && old_item->cells[old_column].custom_button;
|
||||
bool is_over_button = it && it->cells[col].custom_button;
|
||||
if (was_over_button || is_over_button) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce useless redraw calls.
|
||||
|
||||
bool hovered_cell_button_changed = (cache.hover_button_index_in_column != old_button_index_in_column);
|
||||
bool hovered_column_changed = (cache.hover_column != old_column);
|
||||
|
||||
// Mouse has moved from row to row, or from cell to cell within same row unless selection mode is full row which saves a useless redraw.
|
||||
bool item_hover_needs_redraw = !cache.hover_header_row && (cache.hover_item != old_item || hovered_cell_button_changed || (select_mode != SELECT_ROW && hovered_column_changed));
|
||||
// Mouse has moved between two different column header sections.
|
||||
bool header_hover_needs_redraw = cache.hover_header_row && cache.hover_header_column != old_header_column;
|
||||
// Mouse has moved between header and "main" areas.
|
||||
bool whole_needs_redraw = cache.hover_header_row != old_header_row;
|
||||
|
||||
if (whole_needs_redraw || header_hover_needs_redraw || item_hover_needs_redraw) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
bool Tree::edit_selected(bool p_force_edit) {
|
||||
TreeItem *s = get_selected();
|
||||
ERR_FAIL_NULL_V_MSG(s, false, "No item selected.");
|
||||
@ -4304,9 +4438,20 @@ void Tree::_notification(int p_what) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_MOUSE_ENTER: {
|
||||
is_mouse_hovering = true;
|
||||
_determine_hovered_item();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_MOUSE_EXIT: {
|
||||
if (cache.hover_type != Cache::CLICK_NONE) {
|
||||
cache.hover_type = Cache::CLICK_NONE;
|
||||
is_mouse_hovering = false;
|
||||
// Clear hovered item cache.
|
||||
if (cache.hover_header_row || cache.hover_item != nullptr) {
|
||||
cache.hover_header_row = false;
|
||||
cache.hover_header_column = -1;
|
||||
cache.hover_item = nullptr;
|
||||
cache.hover_column = -1;
|
||||
cache.hover_button_index_in_column = -1;
|
||||
queue_redraw();
|
||||
}
|
||||
} break;
|
||||
@ -4420,7 +4565,7 @@ void Tree::_notification(int p_what) {
|
||||
//title buttons
|
||||
int ofs2 = theme_cache.panel_style->get_margin(SIDE_LEFT);
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? theme_cache.title_button_hover : theme_cache.title_button);
|
||||
Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_header_row && cache.hover_header_column == i) ? theme_cache.title_button_hover : theme_cache.title_button);
|
||||
Rect2 tbrect = Rect2(ofs2 - theme_cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh);
|
||||
if (cache.rtl) {
|
||||
tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x;
|
||||
@ -4536,6 +4681,8 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_index) {
|
||||
}
|
||||
}
|
||||
|
||||
_determine_hovered_item();
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
@ -4679,6 +4826,8 @@ void Tree::clear() {
|
||||
popup_edited_item = nullptr;
|
||||
popup_pressing_edited_item = nullptr;
|
||||
|
||||
_determine_hovered_item();
|
||||
|
||||
queue_redraw();
|
||||
};
|
||||
|
||||
@ -4931,6 +5080,7 @@ int Tree::get_columns() const {
|
||||
}
|
||||
|
||||
void Tree::_scroll_moved(float) {
|
||||
_determine_hovered_item();
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
@ -4972,7 +5122,47 @@ int Tree::get_item_offset(TreeItem *p_item) const {
|
||||
}
|
||||
}
|
||||
|
||||
return -1; //not found
|
||||
return -1; // Not found.
|
||||
}
|
||||
|
||||
int Tree::_get_item_h_offset(TreeItem *p_item) const {
|
||||
TreeItem *it = root;
|
||||
int nesting_level = 0;
|
||||
if (!it) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (it == p_item) {
|
||||
if (!hide_root) {
|
||||
nesting_level += 1;
|
||||
}
|
||||
if (hide_folding) {
|
||||
nesting_level -= 1;
|
||||
}
|
||||
return nesting_level * theme_cache.item_margin;
|
||||
}
|
||||
|
||||
if (it->first_child && !it->collapsed) {
|
||||
it = it->first_child;
|
||||
nesting_level += 1;
|
||||
|
||||
} else if (it->next) {
|
||||
it = it->next;
|
||||
} else {
|
||||
while (!it->next) {
|
||||
it = it->parent;
|
||||
nesting_level -= 1;
|
||||
if (it == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
it = it->next;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // Not found.
|
||||
}
|
||||
|
||||
void Tree::ensure_cursor_is_visible() {
|
||||
@ -5803,10 +5993,13 @@ void Tree::_bind_methods() {
|
||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT, Tree, tb_font, "title_button_font");
|
||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT_SIZE, Tree, tb_font_size, "title_button_font_size");
|
||||
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, hovered);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, hovered_dimmed);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected_focus);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor);
|
||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor_unfocus, "cursor_unfocused");
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, button_hover);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, button_pressed);
|
||||
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, checked);
|
||||
@ -5827,6 +6020,8 @@ void Tree::_bind_methods() {
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, custom_button_font_highlight);
|
||||
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_hovered_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_hovered_dimmed_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_selected_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_disabled_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, drop_position_color);
|
||||
|
@ -450,6 +450,9 @@ private:
|
||||
Vector2 pressing_pos;
|
||||
Rect2 pressing_item_rect;
|
||||
|
||||
Vector2 hovered_pos;
|
||||
bool is_mouse_hovering = false;
|
||||
|
||||
float range_drag_base = 0.0;
|
||||
bool range_drag_enabled = false;
|
||||
Vector2 range_drag_capture_pos;
|
||||
@ -545,10 +548,13 @@ private:
|
||||
int font_size = 0;
|
||||
int tb_font_size = 0;
|
||||
|
||||
Ref<StyleBox> hovered;
|
||||
Ref<StyleBox> hovered_dimmed;
|
||||
Ref<StyleBox> selected;
|
||||
Ref<StyleBox> selected_focus;
|
||||
Ref<StyleBox> cursor;
|
||||
Ref<StyleBox> cursor_unfocus;
|
||||
Ref<StyleBox> button_hover;
|
||||
Ref<StyleBox> button_pressed;
|
||||
Ref<StyleBox> title_button;
|
||||
Ref<StyleBox> title_button_hover;
|
||||
@ -572,6 +578,8 @@ private:
|
||||
Ref<Texture2D> updown;
|
||||
|
||||
Color font_color;
|
||||
Color font_hovered_color;
|
||||
Color font_hovered_dimmed_color;
|
||||
Color font_selected_color;
|
||||
Color font_disabled_color;
|
||||
Color guide_color;
|
||||
@ -623,16 +631,17 @@ private:
|
||||
};
|
||||
|
||||
ClickType click_type = Cache::CLICK_NONE;
|
||||
ClickType hover_type = Cache::CLICK_NONE;
|
||||
int click_index = -1;
|
||||
int click_id = -1;
|
||||
TreeItem *click_item = nullptr;
|
||||
int click_column = 0;
|
||||
int hover_index = -1;
|
||||
int hover_header_column = -1;
|
||||
bool hover_header_row = false;
|
||||
Point2 click_pos;
|
||||
|
||||
TreeItem *hover_item = nullptr;
|
||||
int hover_cell = -1;
|
||||
int hover_column = -1;
|
||||
int hover_button_index_in_column = -1;
|
||||
|
||||
bool rtl = false;
|
||||
} cache;
|
||||
@ -660,6 +669,7 @@ private:
|
||||
TreeItem *_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards = false);
|
||||
|
||||
TreeItem *_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int §ion) const;
|
||||
int _get_item_h_offset(TreeItem *p_item) const;
|
||||
|
||||
void _find_button_at_pos(const Point2 &p_pos, TreeItem *&r_item, int &r_column, int &r_index) const;
|
||||
|
||||
@ -689,6 +699,8 @@ private:
|
||||
|
||||
bool enable_recursive_folding = true;
|
||||
|
||||
void _determine_hovered_item();
|
||||
|
||||
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;
|
||||
|
@ -833,10 +833,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
||||
|
||||
theme->set_stylebox(SceneStringName(panel), "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
|
||||
theme->set_stylebox("focus", "Tree", focus);
|
||||
theme->set_stylebox("hovered", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.07)));
|
||||
theme->set_stylebox("hovered_dimmed", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.03)));
|
||||
theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color));
|
||||
theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color));
|
||||
theme->set_stylebox("cursor", "Tree", focus);
|
||||
theme->set_stylebox("cursor_unfocused", "Tree", focus);
|
||||
theme->set_stylebox("button_hover", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.07)));
|
||||
theme->set_stylebox("button_pressed", "Tree", button_pressed);
|
||||
theme->set_stylebox("title_button_normal", "Tree", make_flat_stylebox(style_pressed_color, 4, 4, 4, 4));
|
||||
theme->set_stylebox("title_button_pressed", "Tree", make_flat_stylebox(style_hover_color, 4, 4, 4, 4));
|
||||
@ -864,6 +867,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
||||
|
||||
theme->set_color("title_button_color", "Tree", control_font_color);
|
||||
theme->set_color(SceneStringName(font_color), "Tree", control_font_low_color);
|
||||
theme->set_color("font_hovered_color", "Tree", control_font_hover_color);
|
||||
theme->set_color("font_hovered_dimmed_color", "Tree", control_font_color);
|
||||
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
|
||||
theme->set_color("font_disabled_color", "Tree", control_font_disabled_color);
|
||||
theme->set_color("font_outline_color", "Tree", Color(0, 0, 0));
|
||||
|
Loading…
Reference in New Issue
Block a user