diff options
Diffstat (limited to 'scene/gui/tree.cpp')
-rw-r--r-- | scene/gui/tree.cpp | 104 |
1 files changed, 75 insertions, 29 deletions
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 18d00d519c..b8fc8004c9 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -748,7 +748,7 @@ TreeItem *TreeItem::get_first_child() const { return first_child; } -TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { +TreeItem *TreeItem::_get_prev_in_tree(bool p_wrap, bool p_include_invisible) { TreeItem *current = this; TreeItem *prev_item = current->get_prev(); @@ -771,7 +771,7 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { } } else { current = prev_item; - while (!current->collapsed && current->first_child) { + while ((!current->collapsed || p_include_invisible) && current->first_child) { //go to the very end current = current->first_child; @@ -786,9 +786,9 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { TreeItem *TreeItem::get_prev_visible(bool p_wrap) { TreeItem *loop = this; - TreeItem *prev_item = this->_get_prev_visible(p_wrap); + TreeItem *prev_item = this->_get_prev_in_tree(p_wrap); while (prev_item && !prev_item->is_visible()) { - prev_item = prev_item->_get_prev_visible(p_wrap); + prev_item = prev_item->_get_prev_in_tree(p_wrap); if (prev_item == loop) { // Check that we haven't looped all the way around to the start. prev_item = nullptr; @@ -798,10 +798,10 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) { return prev_item; } -TreeItem *TreeItem::_get_next_visible(bool p_wrap) { +TreeItem *TreeItem::_get_next_in_tree(bool p_wrap, bool p_include_invisible) { TreeItem *current = this; - if (!current->collapsed && current->first_child) { + if ((!current->collapsed || p_include_invisible) && current->first_child) { current = current->first_child; } else if (current->next) { @@ -827,9 +827,9 @@ TreeItem *TreeItem::_get_next_visible(bool p_wrap) { TreeItem *TreeItem::get_next_visible(bool p_wrap) { TreeItem *loop = this; - TreeItem *next_item = this->_get_next_visible(p_wrap); + TreeItem *next_item = this->_get_next_in_tree(p_wrap); while (next_item && !next_item->is_visible()) { - next_item = next_item->_get_next_visible(p_wrap); + next_item = next_item->_get_next_in_tree(p_wrap); if (next_item == loop) { // Check that we haven't looped all the way around to the start. next_item = nullptr; @@ -839,6 +839,16 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) { return next_item; } +TreeItem *TreeItem::get_prev_in_tree(bool p_wrap) { + TreeItem *prev_item = this->_get_prev_in_tree(p_wrap, true); + return prev_item; +} + +TreeItem *TreeItem::get_next_in_tree(bool p_wrap) { + TreeItem *next_item = this->_get_next_in_tree(p_wrap, true); + return next_item; +} + TreeItem *TreeItem::get_child(int p_index) { _create_children_cache(); @@ -1539,6 +1549,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent); ClassDB::bind_method(D_METHOD("get_first_child"), &TreeItem::get_first_child); + ClassDB::bind_method(D_METHOD("get_next_in_tree", "wrap"), &TreeItem::get_next_in_tree, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_prev_in_tree", "wrap"), &TreeItem::get_prev_in_tree, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false)); @@ -1773,7 +1786,7 @@ int Tree::get_item_height(TreeItem *p_item) const { return height; } -void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Point2 &p_draw_ofs, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) { +void Tree::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) { ERR_FAIL_COND(theme_cache.font.is_null()); Rect2i rect = p_rect; @@ -1811,8 +1824,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Po if (rtl && rect.size.width > 0) { Point2 draw_pos = rect.position; - draw_pos.y += Math::floor(p_draw_ofs.y) - _get_title_button_height(); - p_cell.text_buf->set_width(rect.size.width); + draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) * 0.5); if (p_ol_size > 0 && p_ol_color.a > 0) { p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color); } @@ -1831,8 +1843,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Po if (!rtl && rect.size.width > 0) { Point2 draw_pos = rect.position; - draw_pos.y += Math::floor(p_draw_ofs.y) - _get_title_button_height(); - p_cell.text_buf->set_width(rect.size.width); + draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) * 0.5); if (p_ol_size > 0 && p_ol_color.a > 0) { p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color); } @@ -1907,6 +1918,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) { font_size = theme_cache.font_size; } p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].language); + p_item->cells.write[p_col].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE); TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext)); p_item->cells.write[p_col].dirty = false; } @@ -1923,7 +1935,7 @@ void Tree::update_item_cache(TreeItem *p_item) { } } -int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item) { +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) { if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) { return -1; //draw no more! } @@ -1936,17 +1948,14 @@ 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); + int label_h = 0; bool rtl = cache.rtl; - /* Calculate height of the label part */ - label_h += theme_cache.v_separation; - /* Draw label, if height fits */ bool skip = (p_item == root && hide_root); - if (!skip && (p_pos.y + label_h - theme_cache.offset.y) > 0) { + if (!skip) { // Draw separation. ERR_FAIL_COND_V(theme_cache.font.is_null(), -1); @@ -2006,6 +2015,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 buttons_width += button_size.width + theme_cache.button_margin; } + p_item->cells.write[i].text_buf->set_width(item_width); + + label_h = compute_item_height(p_item); + if (r_self_height != nullptr) { + *r_self_height = label_h; + } + label_h += theme_cache.v_separation; + Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(item_width, label_h)); Rect2i cell_rect = item_rect; if (i != 0) { @@ -2129,7 +2146,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.write[i], item_rect, p_draw_ofs, cell_color, icon_col, outline_size, font_outline_color); + draw_item_rect(p_item->cells.write[i], item_rect, cell_color, icon_col, outline_size, font_outline_color); } break; case TreeItem::CELL_MODE_CHECK: { Ref<Texture2D> checked = theme_cache.checked; @@ -2153,7 +2170,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 item_rect.size.x -= check_w; item_rect.position.x += check_w; - draw_item_rect(p_item->cells.write[i], item_rect, p_draw_ofs, cell_color, icon_col, outline_size, font_outline_color); + draw_item_rect(p_item->cells.write[i], item_rect, cell_color, icon_col, outline_size, font_outline_color); } break; case TreeItem::CELL_MODE_RANGE: { @@ -2165,7 +2182,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 Ref<Texture2D> downarrow = theme_cache.select_arrow; int cell_width = item_rect.size.x - downarrow->get_width(); - p_item->cells.write[i].text_buf->set_width(cell_width); if (rtl) { if (outline_size > 0 && font_outline_color.a > 0) { p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color); @@ -2232,7 +2248,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.write[i], item_rect, p_draw_ofs, cell_color, icon_col, outline_size, font_outline_color); + draw_item_rect(p_item->cells.write[i], item_rect, cell_color, icon_col, outline_size, font_outline_color); break; } @@ -2260,7 +2276,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.write[i], ir, p_draw_ofs, cell_color, icon_col, outline_size, font_outline_color); + draw_item_rect(p_item->cells.write[i], ir, cell_color, icon_col, outline_size, font_outline_color); downarrow->draw(ci, arrow_pos); @@ -2352,15 +2368,17 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 while (c) { 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_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, &child_self_height); + child_self_height += theme_cache.v_separation; } // Draw relationship lines. if (theme_cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.h_separation : theme_cache.item_margin); int parent_ofs = p_pos.x + theme_cache.item_margin; - Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - theme_cache.offset + p_draw_ofs; + Point2i root_pos = Point2i(root_ofs, children_pos.y + child_self_height / 2) - theme_cache.offset + p_draw_ofs; if (c->get_visible_child_count() > 0) { root_pos -= Point2i(theme_cache.arrow->get_width(), 0); @@ -3846,14 +3864,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } } -bool Tree::edit_selected() { +bool Tree::edit_selected(bool p_force_edit) { TreeItem *s = get_selected(); ERR_FAIL_COND_V_MSG(!s, false, "No item selected."); ensure_cursor_is_visible(); int col = get_selected_column(); ERR_FAIL_INDEX_V_MSG(col, columns.size(), false, "No item column selected."); - if (!s->cells[col].editable) { + if (!s->cells[col].editable && !p_force_edit) { return false; } @@ -3959,6 +3977,14 @@ bool Tree::is_editing() { return popup_editor->is_visible(); } +void Tree::set_editor_selection(int p_from_line, int p_to_line, int p_from_column, int p_to_column, int p_caret) { + if (p_from_column == -1 || p_to_column == -1) { + line_editor->select(p_from_line, p_to_line); + } else { + text_editor->select(p_from_line, p_from_column, p_to_line, p_to_column, p_caret); + } +} + Size2 Tree::get_internal_min_size() const { Size2i size; if (root) { @@ -4990,6 +5016,26 @@ TreeItem *Tree::get_item_with_text(const String &p_find) const { return nullptr; } +TreeItem *Tree::get_item_with_metadata(const Variant &p_find, int p_column) const { + if (p_column < 0) { + for (TreeItem *current = root; current; current = current->get_next_in_tree()) { + for (int i = 0; i < columns.size(); i++) { + if (current->get_metadata(i) == p_find) { + return current; + } + } + } + return nullptr; + } + + for (TreeItem *current = root; current; current = current->get_next_in_tree()) { + if (current->get_metadata(p_column) == p_find) { + return current; + } + } + return nullptr; +} + void Tree::_do_incr_search(const String &p_add) { uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec uint64_t diff = time - last_keypress; @@ -5355,7 +5401,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited"), &Tree::get_edited); ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column); - ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected); + ClassDB::bind_method(D_METHOD("edit_selected", "force_edit"), &Tree::edit_selected, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect); ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column", "button_index"), &Tree::get_item_rect, DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position); |