|
|
|
@@ -122,6 +122,7 @@ void TreeItem::_change_tree(Tree *p_tree) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
tree->sticky_list.clear();
|
|
|
|
|
if (tree->root == this) {
|
|
|
|
|
tree->root = nullptr;
|
|
|
|
|
}
|
|
|
|
@@ -2129,7 +2130,7 @@ Rect2i Tree::convert_rtl_rect(const Rect2i &p_rect) const {
|
|
|
|
|
return p_rect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tree::draw_item_rect(const 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) const {
|
|
|
|
|
void Tree::draw_item_rect(const 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, const RID &p_ci) const {
|
|
|
|
|
ERR_FAIL_COND(theme_cache.font.is_null());
|
|
|
|
|
|
|
|
|
|
Rect2i rect = p_rect;
|
|
|
|
@@ -2169,7 +2170,7 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RID ci = content_ci;
|
|
|
|
|
RID ci = p_ci;
|
|
|
|
|
|
|
|
|
|
if (rtl) {
|
|
|
|
|
if (ts.width > 0) {
|
|
|
|
@@ -2319,7 +2320,7 @@ void Tree::update_item_cache(TreeItem *p_item) const {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height) {
|
|
|
|
|
int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height, const RID &p_ci) {
|
|
|
|
|
const real_t bottom_margin = theme_cache.panel_style->get_margin(SIDE_BOTTOM); // Extra stylebox space below the content
|
|
|
|
|
const real_t draw_height = p_draw_size.height + bottom_margin; // Visible height including bottom margin
|
|
|
|
|
|
|
|
|
@@ -2332,9 +2333,11 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RID ci = content_ci;
|
|
|
|
|
RID ci = p_ci;
|
|
|
|
|
RID sb_ci = ci == content_ci ? stylebox_ci : ci;
|
|
|
|
|
|
|
|
|
|
int htotal = 0;
|
|
|
|
|
int htotal_raw = 0;
|
|
|
|
|
|
|
|
|
|
int label_h = 0;
|
|
|
|
|
bool rtl = cache.rtl;
|
|
|
|
@@ -2444,22 +2447,22 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
if (p_item->cells[0].selected) {
|
|
|
|
|
if (is_row_hovered) {
|
|
|
|
|
if (has_focus(true)) {
|
|
|
|
|
theme_cache.hovered_selected_focus->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.hovered_selected_focus->draw(sb_ci, row_rect);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.hovered_selected->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.hovered_selected->draw(sb_ci, row_rect);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (has_focus(true)) {
|
|
|
|
|
theme_cache.selected_focus->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.selected_focus->draw(sb_ci, row_rect);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.selected->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.selected->draw(sb_ci, row_rect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (!drop_mode_flags) {
|
|
|
|
|
if (is_cell_button_hovered) {
|
|
|
|
|
theme_cache.hovered_dimmed->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.hovered_dimmed->draw(sb_ci, row_rect);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.hovered->draw(stylebox_ci, row_rect);
|
|
|
|
|
theme_cache.hovered->draw(sb_ci, row_rect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -2471,9 +2474,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
// Cell hover.
|
|
|
|
|
if (is_cell_hovered && !p_item->cells[i].selected && !drop_mode_flags) {
|
|
|
|
|
if (is_cell_button_hovered) {
|
|
|
|
|
theme_cache.hovered_dimmed->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.hovered_dimmed->draw(sb_ci, r);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.hovered->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.hovered->draw(sb_ci, r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -2487,15 +2490,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
if (p_item->cells[i].selected) {
|
|
|
|
|
if (is_cell_hovered) {
|
|
|
|
|
if (has_focus(true)) {
|
|
|
|
|
theme_cache.hovered_selected_focus->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.hovered_selected_focus->draw(sb_ci, r);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.hovered_selected->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.hovered_selected->draw(sb_ci, r);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (has_focus(true)) {
|
|
|
|
|
theme_cache.selected_focus->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.selected_focus->draw(sb_ci, r);
|
|
|
|
|
} else {
|
|
|
|
|
theme_cache.selected->draw(stylebox_ci, r);
|
|
|
|
|
theme_cache.selected->draw(sb_ci, r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -2561,7 +2564,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
|
|
|
|
|
switch (p_item->cells[i].mode) {
|
|
|
|
|
case TreeItem::CELL_MODE_STRING: {
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color);
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color, ci);
|
|
|
|
|
} break;
|
|
|
|
|
case TreeItem::CELL_MODE_CHECK: {
|
|
|
|
|
Point2i check_ofs = item_rect.position;
|
|
|
|
@@ -2596,7 +2599,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
cell_color = theme_cache.font_disabled_color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color);
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color, ci);
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
case TreeItem::CELL_MODE_RANGE: {
|
|
|
|
@@ -2679,7 +2682,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!p_item->cells[i].editable) {
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color);
|
|
|
|
|
draw_item_rect(p_item->cells[i], item_rect, cell_color, icon_col, outline_size, font_outline_color, ci);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2707,7 +2710,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
ir.position += theme_cache.custom_button->get_offset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
draw_item_rect(p_item->cells[i], ir, cell_color, icon_col, outline_size, font_outline_color);
|
|
|
|
|
draw_item_rect(p_item->cells[i], ir, cell_color, icon_col, outline_size, font_outline_color, ci);
|
|
|
|
|
|
|
|
|
|
downarrow->draw(ci, arrow_pos);
|
|
|
|
|
|
|
|
|
@@ -2808,10 +2811,11 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
if (!skip) {
|
|
|
|
|
children_pos.x += theme_cache.item_margin;
|
|
|
|
|
htotal += label_h;
|
|
|
|
|
children_pos.y += htotal;
|
|
|
|
|
htotal_raw += label_h;
|
|
|
|
|
children_pos.y += htotal_raw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!p_item->collapsed) { // If not collapsed, check the children.
|
|
|
|
|
if (!p_item->collapsed && p_ci == content_ci) { // If not collapsed, check the children.
|
|
|
|
|
TreeItem *c = p_item->first_child;
|
|
|
|
|
|
|
|
|
|
int base_ofs = children_pos.y - theme_cache.offset.y + p_draw_ofs.y;
|
|
|
|
@@ -2823,7 +2827,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
int child_h = -1;
|
|
|
|
|
int child_self_height = 0;
|
|
|
|
|
if (htotal >= 0) {
|
|
|
|
|
child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, child_self_height);
|
|
|
|
|
child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, child_self_height, ci);
|
|
|
|
|
child_self_height += theme_cache.v_separation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2940,7 +2944,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
break; // Last loop done, stop.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (theme_cache.draw_relationship_lines == 0) {
|
|
|
|
|
if (theme_cache.draw_relationship_lines == 0 && theme_cache.scroll_max_sticky_items == 0) {
|
|
|
|
|
return -1; // No need to draw anymore, full stop.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2948,6 +2952,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
children_pos.y = theme_cache.offset.y + draw_height;
|
|
|
|
|
} else {
|
|
|
|
|
htotal += child_h;
|
|
|
|
|
htotal_raw += child_h;
|
|
|
|
|
children_pos.y += child_h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2955,7 +2960,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return htotal;
|
|
|
|
|
if (theme_cache.scroll_max_sticky_items > 0 && p_ci == content_ci && !p_item->collapsed) {
|
|
|
|
|
sticky_candidates.push_back(p_item);
|
|
|
|
|
p_item->cached_start = p_pos.y;
|
|
|
|
|
p_item->cached_total_end = p_pos.y + htotal_raw;
|
|
|
|
|
p_item->cached_label_height = label_h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return htotal_raw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Tree::_count_selected_items(TreeItem *p_from) const {
|
|
|
|
@@ -3145,7 +3157,24 @@ void Tree::_range_click_timeout() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, MouseButton p_button, const Ref<InputEventWithModifiers> &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, MouseButton p_button, const Ref<InputEventWithModifiers> &p_mod, bool p_first_call, bool p_skip_children) {
|
|
|
|
|
if (p_first_call) {
|
|
|
|
|
// Handle sticky item input first
|
|
|
|
|
for (TreeItem *item : sticky_list) {
|
|
|
|
|
Point2 relative_pos = p_pos;
|
|
|
|
|
relative_pos.y -= theme_cache.offset.y;
|
|
|
|
|
relative_pos.y -= item->sticky_offset.y;
|
|
|
|
|
if (relative_pos.y > item->cached_label_height) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
int result = propagate_mouse_event(relative_pos, x_ofs, y_ofs, x_limit, p_double_click, item, p_button, p_mod, false, true);
|
|
|
|
|
if (result < 0) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p_first_call = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p_item && !p_item->is_visible_in_tree()) {
|
|
|
|
|
// Skip any processing of invisible items.
|
|
|
|
|
return 0;
|
|
|
|
@@ -3257,12 +3286,18 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
|
|
|
|
|
if (select_mode == SELECT_MULTI && icount > 1 && p_button != MouseButton::RIGHT) {
|
|
|
|
|
if (!already_selected) {
|
|
|
|
|
select_single_item(p_item, root, col);
|
|
|
|
|
if (p_skip_children) {
|
|
|
|
|
ensure_cursor_is_visible();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
single_select_defer = p_item;
|
|
|
|
|
single_select_defer_column = col;
|
|
|
|
|
} else {
|
|
|
|
|
if (p_button != MouseButton::RIGHT || !c.selected) {
|
|
|
|
|
select_single_item(p_item, root, col);
|
|
|
|
|
if (p_skip_children && p_button != MouseButton::RIGHT) {
|
|
|
|
|
ensure_cursor_is_visible();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
|
|
|
|
@@ -3409,12 +3444,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
|
|
|
|
|
new_pos.y -= item_h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!p_item->collapsed) { // If not collapsed, check the children.
|
|
|
|
|
if ((p_item && !p_item->collapsed) && !p_skip_children) { // If not collapsed, check the children.
|
|
|
|
|
|
|
|
|
|
TreeItem *c = p_item->first_child;
|
|
|
|
|
|
|
|
|
|
while (c) {
|
|
|
|
|
int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, x_limit, 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, false, false);
|
|
|
|
|
|
|
|
|
|
if (child_h < 0) {
|
|
|
|
|
return -1; // Break, stop propagating, no need to anymore.
|
|
|
|
@@ -5251,12 +5286,16 @@ void Tree::_notification(int p_what) {
|
|
|
|
|
rendering_server->canvas_item_set_custom_rect(drop_indicator_ci, !is_visibility_clip_disabled(), main_clip_rect);
|
|
|
|
|
rendering_server->canvas_item_set_clip(drop_indicator_ci, true);
|
|
|
|
|
|
|
|
|
|
rendering_server->canvas_item_clear(last_sticky_ci);
|
|
|
|
|
rendering_server->canvas_item_set_clip(last_sticky_ci, true);
|
|
|
|
|
|
|
|
|
|
cache.rtl = is_layout_rtl();
|
|
|
|
|
content_scale_factor = popup_editor->is_embedded() ? 1.0 : popup_editor->get_parent_visible_window()->get_content_scale_factor();
|
|
|
|
|
|
|
|
|
|
sticky_candidates.clear();
|
|
|
|
|
if (root && get_size().x > 0 && get_size().y > 0) {
|
|
|
|
|
int self_height = 0; // Just to pass a reference, we don't need the root's `self_height`.
|
|
|
|
|
draw_item(Point2(), draw_ofs, draw_size, root, self_height);
|
|
|
|
|
draw_item(Point2(), draw_ofs, draw_size, root, self_height, content_ci);
|
|
|
|
|
|
|
|
|
|
// Draw drop indicator.
|
|
|
|
|
if (drop_mode_flags && drop_mode_over) {
|
|
|
|
@@ -5511,6 +5550,55 @@ void Tree::_notification(int p_what) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sticky_stack_end = 0;
|
|
|
|
|
if (root) {
|
|
|
|
|
sticky_list.clear();
|
|
|
|
|
Vector2 stick_ofs;
|
|
|
|
|
Vector2 last_ofs = stick_ofs;
|
|
|
|
|
real_t height_limit = get_size().y * .4; // Prevent sticky items from ever exceeding 40% of the space
|
|
|
|
|
|
|
|
|
|
// Filter sticky candidates and cache their sticky positions
|
|
|
|
|
for (int i = sticky_candidates.size() - 1; i >= 0; i--) {
|
|
|
|
|
TreeItem *item = sticky_candidates[i];
|
|
|
|
|
bool past_top = item->cached_start - theme_cache.offset.y < stick_ofs.y;
|
|
|
|
|
bool stickable = !item->collapsed && item->get_child_count() > 0;
|
|
|
|
|
bool hidden_root = hide_root && item == root;
|
|
|
|
|
if (past_top && stickable && !hidden_root) {
|
|
|
|
|
if (item->cached_total_end - theme_cache.offset.y > stick_ofs.y) {
|
|
|
|
|
last_ofs = stick_ofs;
|
|
|
|
|
stick_ofs.y = MIN(stick_ofs.y, item->cached_total_end - theme_cache.offset.y - item->cached_label_height);
|
|
|
|
|
item->sticky_offset = stick_ofs;
|
|
|
|
|
sticky_list.push_back(item);
|
|
|
|
|
stick_ofs.x += theme_cache.item_margin;
|
|
|
|
|
stick_ofs.y += item->cached_label_height;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((int)sticky_list.size() >= theme_cache.scroll_max_sticky_items || stick_ofs.y >= height_limit) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sticky_stack_end = stick_ofs.y;
|
|
|
|
|
for (int i = sticky_list.size() - 1; i >= 0; i--) {
|
|
|
|
|
bool is_last = i == (int)sticky_list.size() - 1;
|
|
|
|
|
TreeItem *item = sticky_list[i];
|
|
|
|
|
|
|
|
|
|
// Draw sticky items without a scroll offset temporarily
|
|
|
|
|
Point2 old_offset = theme_cache.offset;
|
|
|
|
|
theme_cache.offset.y = 0;
|
|
|
|
|
int self_height = 0;
|
|
|
|
|
draw_item(item->sticky_offset, draw_ofs, draw_size, item, self_height, is_last ? last_sticky_ci : header_ci);
|
|
|
|
|
theme_cache.offset = old_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sticky_list.is_empty()) {
|
|
|
|
|
rendering_server->canvas_item_set_custom_rect(last_sticky_ci, !is_visibility_clip_disabled(), Rect2(0, last_ofs.y + draw_ofs.y, get_size().x, sticky_stack_end - last_ofs.y));
|
|
|
|
|
rendering_server->canvas_item_set_custom_rect(content_ci, !is_visibility_clip_disabled(), main_clip_rect.grow_side(SIDE_TOP, -(sticky_stack_end + content_rect.position.y)));
|
|
|
|
|
rendering_server->canvas_item_set_custom_rect(stylebox_ci, !is_visibility_clip_disabled(), main_clip_rect.grow_side(SIDE_TOP, -(sticky_stack_end + content_rect.position.y)));
|
|
|
|
|
rendering_server->canvas_item_set_custom_rect(header_ci, !is_visibility_clip_disabled(), header_clip_rect.grow_side(SIDE_BOTTOM, last_ofs.y + content_rect.position.y));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scroll_hint_mode != SCROLL_HINT_MODE_DISABLED) {
|
|
|
|
|
Size2 size = get_size();
|
|
|
|
|
float v_scroll_value = v_scroll->get_value();
|
|
|
|
@@ -5518,7 +5606,7 @@ void Tree::_notification(int p_what) {
|
|
|
|
|
if (v_scroll_value > 1 || v_scroll_below_max) {
|
|
|
|
|
int hint_height = theme_cache.scroll_hint->get_height();
|
|
|
|
|
if ((scroll_hint_mode == SCROLL_HINT_MODE_BOTH || scroll_hint_mode == SCROLL_HINT_MODE_TOP) && v_scroll_value > 1) {
|
|
|
|
|
draw_texture_rect(theme_cache.scroll_hint, Rect2(Point2(), Size2(size.width, hint_height)), tile_scroll_hint, theme_cache.scroll_hint_color);
|
|
|
|
|
draw_texture_rect(theme_cache.scroll_hint, Rect2(0, sticky_stack_end > 0 ? sticky_stack_end + draw_ofs.y : 0, size.width, hint_height), tile_scroll_hint, theme_cache.scroll_hint_color);
|
|
|
|
|
}
|
|
|
|
|
if ((scroll_hint_mode == SCROLL_HINT_MODE_BOTH || scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM) && v_scroll_below_max) {
|
|
|
|
|
draw_texture_rect(theme_cache.scroll_hint, Rect2(Point2(0, size.height - hint_height), Size2(size.width, -hint_height)), tile_scroll_hint, theme_cache.scroll_hint_color);
|
|
|
|
@@ -5561,6 +5649,7 @@ void Tree::set_self_modulate(const Color &p_self_modulate) {
|
|
|
|
|
|
|
|
|
|
CanvasItem::set_self_modulate(p_self_modulate);
|
|
|
|
|
RS::get_singleton()->canvas_item_set_self_modulate(header_ci, p_self_modulate);
|
|
|
|
|
RS::get_singleton()->canvas_item_set_self_modulate(last_sticky_ci, p_self_modulate);
|
|
|
|
|
RS::get_singleton()->canvas_item_set_self_modulate(content_ci, p_self_modulate);
|
|
|
|
|
RS::get_singleton()->canvas_item_set_self_modulate(custom_ci, p_self_modulate);
|
|
|
|
|
RS::get_singleton()->canvas_item_set_self_modulate(stylebox_ci, p_self_modulate);
|
|
|
|
@@ -6131,8 +6220,21 @@ void Tree::ensure_cursor_is_visible() {
|
|
|
|
|
const int tbh = _get_title_button_height();
|
|
|
|
|
y_offset -= tbh;
|
|
|
|
|
|
|
|
|
|
bool selected_is_sticky = false;
|
|
|
|
|
for (TreeItem *item : sticky_list) {
|
|
|
|
|
if (selected_item == item) {
|
|
|
|
|
y_offset -= item->sticky_offset.y;
|
|
|
|
|
selected_is_sticky = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!selected_is_sticky) {
|
|
|
|
|
y_offset -= sticky_stack_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int cell_h = compute_item_height(selected_item) + theme_cache.v_separation;
|
|
|
|
|
int screen_h = area_size.height - tbh;
|
|
|
|
|
int screen_h = area_size.height - tbh - sticky_stack_end;
|
|
|
|
|
|
|
|
|
|
if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet.
|
|
|
|
|
delta_v = y_offset - v_scroll->get_value();
|
|
|
|
@@ -6555,7 +6657,7 @@ void Tree::_do_incr_search(const String &p_add) {
|
|
|
|
|
ensure_cursor_is_visible();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &r_height, int &r_section) const {
|
|
|
|
|
TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &r_height, int &r_section, bool p_sticky_check) const {
|
|
|
|
|
r_column = -1;
|
|
|
|
|
r_height = 0;
|
|
|
|
|
r_section = COLUMN_NOT_FOUND;
|
|
|
|
@@ -6564,6 +6666,16 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p_sticky_check) {
|
|
|
|
|
Point2 relative_pos = p_pos - theme_cache.offset;
|
|
|
|
|
for (TreeItem *item : sticky_list) {
|
|
|
|
|
if (item && relative_pos.y >= item->sticky_offset.y && relative_pos.y < item->sticky_offset.y + item->cached_label_height) {
|
|
|
|
|
item = _find_item_at_pos(item, relative_pos - Point2(0, item->cached_start), r_column, r_height, r_section, false);
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Point2 pos = p_pos;
|
|
|
|
|
|
|
|
|
|
// Calculate target parent based on horizontal mouse position.
|
|
|
|
@@ -6690,7 +6802,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
|
|
|
|
|
TreeItem *n = p_item->get_first_child();
|
|
|
|
|
while (n) {
|
|
|
|
|
int ch;
|
|
|
|
|
TreeItem *r = _find_item_at_pos(n, pos, r_column, ch, r_section);
|
|
|
|
|
TreeItem *r = _find_item_at_pos(n, pos, r_column, ch, r_section, false);
|
|
|
|
|
pos.y -= ch;
|
|
|
|
|
r_height += ch;
|
|
|
|
|
if (r) {
|
|
|
|
@@ -7406,6 +7518,7 @@ void Tree::_bind_methods() {
|
|
|
|
|
|
|
|
|
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scroll_border);
|
|
|
|
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scroll_speed);
|
|
|
|
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scroll_max_sticky_items);
|
|
|
|
|
|
|
|
|
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_top);
|
|
|
|
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_right);
|
|
|
|
@@ -7455,6 +7568,10 @@ Tree::Tree() {
|
|
|
|
|
rs->canvas_item_set_parent(drop_indicator_ci, get_canvas_item());
|
|
|
|
|
rs->canvas_item_set_use_parent_material(drop_indicator_ci, true);
|
|
|
|
|
|
|
|
|
|
last_sticky_ci = rs->canvas_item_create();
|
|
|
|
|
rs->canvas_item_set_parent(last_sticky_ci, get_canvas_item());
|
|
|
|
|
rs->canvas_item_set_use_parent_material(last_sticky_ci, true);
|
|
|
|
|
|
|
|
|
|
popup_editor = memnew(Popup);
|
|
|
|
|
add_child(popup_editor, false, INTERNAL_MODE_FRONT);
|
|
|
|
|
|
|
|
|
@@ -7512,4 +7629,5 @@ Tree::~Tree() {
|
|
|
|
|
RenderingServer::get_singleton()->free_rid(header_ci);
|
|
|
|
|
RenderingServer::get_singleton()->free_rid(custom_ci);
|
|
|
|
|
RenderingServer::get_singleton()->free_rid(stylebox_ci);
|
|
|
|
|
RenderingServer::get_singleton()->free_rid(last_sticky_ci);
|
|
|
|
|
}
|
|
|
|
|