diff options
Diffstat (limited to 'scene/gui')
-rw-r--r-- | scene/gui/base_button.cpp | 222 | ||||
-rw-r--r-- | scene/gui/base_button.h | 3 | ||||
-rw-r--r-- | scene/gui/control.cpp | 10 | ||||
-rw-r--r-- | scene/gui/file_dialog.cpp | 4 | ||||
-rw-r--r-- | scene/gui/gradient_edit.cpp | 9 | ||||
-rw-r--r-- | scene/gui/gradient_edit.h | 2 | ||||
-rw-r--r-- | scene/gui/graph_node.cpp | 4 | ||||
-rw-r--r-- | scene/gui/item_list.cpp | 25 | ||||
-rw-r--r-- | scene/gui/line_edit.cpp | 40 | ||||
-rw-r--r-- | scene/gui/option_button.cpp | 1 | ||||
-rw-r--r-- | scene/gui/popup.cpp | 13 | ||||
-rw-r--r-- | scene/gui/popup.h | 1 | ||||
-rw-r--r-- | scene/gui/popup_menu.cpp | 56 | ||||
-rw-r--r-- | scene/gui/popup_menu.h | 7 | ||||
-rw-r--r-- | scene/gui/rich_text_label.cpp | 3 | ||||
-rw-r--r-- | scene/gui/scroll_bar.cpp | 16 | ||||
-rw-r--r-- | scene/gui/scroll_container.cpp | 13 | ||||
-rw-r--r-- | scene/gui/slider.cpp | 1 | ||||
-rw-r--r-- | scene/gui/spin_box.cpp | 1 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 148 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 7 | ||||
-rw-r--r-- | scene/gui/tree.cpp | 65 | ||||
-rw-r--r-- | scene/gui/tree.h | 4 |
23 files changed, 371 insertions, 284 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index e95781c181..fadf5e432c 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -56,185 +56,53 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { if (status.disabled) // no interaction with disabled button return; - Ref<InputEventMouseButton> b = p_event; + Ref<InputEventMouseButton> mouse_button = p_event; + bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); - if (b.is_valid()) { - if (((1 << (b->get_button_index() - 1)) & button_mask) == 0) - return; - - if (status.pressing_button) - return; - - if (action_mode == ACTION_MODE_BUTTON_PRESS) { - - if (b->is_pressed()) { - - emit_signal("button_down"); - - if (!toggle_mode) { //mouse press attempt - - status.press_attempt = true; - status.pressing_inside = true; + bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; + if (button_masked || ui_accept) { + if (p_event->is_pressed()) { + status.press_attempt = true; + status.pressing_inside = true; + emit_signal("button_down"); + } - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); + if (status.press_attempt && status.pressing_inside) { + if (toggle_mode) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { + if (action_mode == ACTION_MODE_BUTTON_PRESS) { + status.press_attempt = false; + status.pressing_inside = false; } - - _unpress_group(); - emit_signal("pressed"); - - } else { - status.pressed = !status.pressed; - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); + _toggled(status.pressed); + _pressed(); } - } else { - - emit_signal("button_up"); - - /* this is pointless if (status.press_attempt && status.pressing_inside) { - //released(); - emit_signal("released"); + if (!p_event->is_pressed()) { + _pressed(); } -*/ - status.press_attempt = false; } - update(); - return; } - if (b->is_pressed()) { - - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else { - + if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal emit_signal("button_up"); - - if (status.press_attempt && status.pressing_inside) { - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - } - status.press_attempt = false; } update(); + return; } - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - if (status.press_attempt && status.pressing_button == 0) { + Ref<InputEventMouseMotion> mouse_motion = p_event; + if (mouse_motion.is_valid()) { + if (status.press_attempt) { bool last_press_inside = status.pressing_inside; - status.pressing_inside = has_point(mm->get_position()); - if (last_press_inside != status.pressing_inside) + status.pressing_inside = has_point(mouse_motion->get_position()); + if (last_press_inside != status.pressing_inside) { update(); - } - } - - if (!mm.is_valid() && !b.is_valid()) { - - if (p_event->is_echo()) { - return; - } - - if (status.disabled) { - return; - } - - if (status.press_attempt && status.pressing_button == 0) { - return; - } - - if (p_event->is_action("ui_accept")) { - - if (p_event->is_pressed()) { - - status.pressing_button++; - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else if (status.press_attempt) { - - if (status.pressing_button) - status.pressing_button--; - - if (status.pressing_button) - return; - - status.press_attempt = false; - status.pressing_inside = false; - - emit_signal("button_up"); - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } } - - accept_event(); - update(); } } } @@ -255,7 +123,6 @@ void BaseButton::_notification(int p_what) { if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; update(); } } @@ -268,9 +135,8 @@ void BaseButton::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_EXIT) { - if (status.pressing_button && status.press_attempt) { + if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; status.hovering = false; update(); } else if (status.hovering) { @@ -290,21 +156,31 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } } -void BaseButton::pressed() { +void BaseButton::_pressed() { - if (get_script_instance()) - get_script_instance()->call("pressed"); + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed); + } + pressed(); + emit_signal("pressed"); } -void BaseButton::toggled(bool p_pressed) { +void BaseButton::_toggled(bool p_pressed) { if (get_script_instance()) { - get_script_instance()->call("toggled", p_pressed); + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed); } + toggled(p_pressed); + emit_signal("toggled", p_pressed); +} + +void BaseButton::pressed() { +} + +void BaseButton::toggled(bool p_pressed) { } void BaseButton::set_disabled(bool p_disabled) { @@ -318,7 +194,6 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } update(); _change_notify("disabled"); @@ -341,6 +216,8 @@ void BaseButton::set_pressed(bool p_pressed) { if (p_pressed) { _unpress_group(); } + _toggled(status.pressed); + update(); } @@ -458,9 +335,6 @@ bool BaseButton::is_keep_pressed_outside() const { void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) { - if (shortcut.is_null() == p_shortcut.is_null()) - return; - shortcut = p_shortcut; set_process_unhandled_input(shortcut.is_valid()); } @@ -477,11 +351,10 @@ void BaseButton::_unhandled_input(Ref<InputEvent> p_event) { return; //ignore because of modal window if (is_toggle_mode()) { - set_pressed(!is_pressed()); - emit_signal("toggled", is_pressed()); + set_pressed(!is_pressed()); // Also calls _toggled() internally. } - emit_signal("pressed"); + _pressed(); } } @@ -585,7 +458,6 @@ BaseButton::BaseButton() { status.hovering = false; status.pressing_inside = false; status.disabled = false; - status.pressing_button = 0; set_focus_mode(FOCUS_ALL); enabled_focus_mode = FOCUS_ALL; action_mode = ACTION_MODE_BUTTON_RELEASE; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 22a8f6d8fe..abb3f58d6b 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -65,13 +65,14 @@ private: bool pressing_inside; bool disabled; - int pressing_button; } status; Ref<ButtonGroup> button_group; void _unpress_group(); + void _pressed(); + void _toggled(bool p_pressed); protected: virtual void pressed(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 76275c2420..9d7c08d3f3 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -29,23 +29,23 @@ /*************************************************************************/ #include "control.h" -#include "core/project_settings.h" -#include "scene/main/canvas_layer.h" -#include "scene/main/viewport.h" -#include "servers/visual_server.h" #include "core/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" +#include "core/project_settings.h" #include "scene/gui/label.h" #include "scene/gui/panel.h" +#include "scene/main/canvas_layer.h" +#include "scene/main/viewport.h" #include "scene/scene_string_names.h" +#include "servers/visual_server.h" + #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #include "editor/plugins/canvas_item_editor_plugin.h" #endif -#include <stdio.h> Dictionary Control::_edit_get_state() const { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 5671b41de8..bdb1342019 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -431,8 +431,6 @@ void FileDialog::update_file_list() { dirs.pop_front(); } - dirs.clear(); - List<String> patterns; // build filter if (filter->get_selected() == filter->get_item_count() - 1) { @@ -507,8 +505,6 @@ void FileDialog::update_file_list() { if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == NULL) tree->get_root()->get_children()->select(0); - - files.clear(); } void FileDialog::_filter_selected(int) { diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index cfbc9d6d18..75f5f79873 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -29,10 +29,17 @@ /*************************************************************************/ #include "gradient_edit.h" + #include "core/os/keyboard.h" -#include "editor/editor_scale.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_scale.h" #define SPACING (3 * EDSCALE) +#define POINT_WIDTH (8 * EDSCALE) +#else +#define SPACING 3 +#define POINT_WIDTH 8 +#endif GradientEdit::GradientEdit() { grabbed = -1; diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index 662278a17b..6f31107729 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -36,8 +36,6 @@ #include "scene/resources/default_theme/theme_data.h" #include "scene/resources/gradient.h" -#define POINT_WIDTH (8 * EDSCALE) - class GradientEdit : public Control { GDCLASS(GradientEdit, Control); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index e8692d56d2..6463ee5ad5 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -159,9 +159,7 @@ void GraphNode::_resort() { fit_child_in_rect(c, r); cache_y.push_back(vofs + size.y * 0.5); - if (vofs > 0) - vofs += sep; - vofs += size.y; + vofs += size.y + sep; } update(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 026374ded1..91b76839d7 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -470,6 +470,8 @@ Size2 ItemList::Item::get_icon_size() const { void ItemList::_gui_input(const Ref<InputEvent> &p_event) { + double prev_scroll = scroll_bar->get_value(); + Ref<InputEventMouseMotion> mm = p_event; if (defer_select_single >= 0 && mm.is_valid()) { defer_select_single = -1; @@ -747,9 +749,21 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { search_string = ""; } - search_string += String::chr(k->get_unicode()); - for (int i = 0; i < items.size(); i++) { - if (items[i].text.begins_with(search_string)) { + if (String::chr(k->get_unicode()) != search_string) + search_string += String::chr(k->get_unicode()); + + for (int i = current + 1; i <= items.size(); i++) { + if (i == items.size()) { + if (current == 0) + break; + else + i = 0; + } + + if (i == current) + break; + + if (items[i].text.findn(search_string) == 0) { set_current(i); ensure_current_is_visible(); if (select_mode == SELECT_SINGLE) { @@ -767,6 +781,9 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8); } + + if (scroll_bar->get_value() != prev_scroll) + accept_event(); //accept event if scroll changed } void ItemList::ensure_current_is_visible() { @@ -1243,7 +1260,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { Rect2 rc = items[i].rect_cache; if (i % current_columns == current_columns - 1) { - rc.size.width = get_size().width; //not right but works + rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column } if (rc.has_point(pos)) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index ed74851755..da6bff8ab8 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -44,7 +44,7 @@ static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return !is_symbol(c); } void LineEdit::_gui_input(Ref<InputEvent> p_event) { @@ -68,6 +68,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { + accept_event(); //don't pass event further when clicked on text field if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; @@ -159,6 +160,38 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (!k->is_pressed()) return; + +#ifdef APPLE_STYLE_KEYS + if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { + uint32_t remap_key = KEY_UNKNOWN; + switch (k->get_scancode()) { + case KEY_F: { + remap_key = KEY_RIGHT; + } break; + case KEY_B: { + remap_key = KEY_LEFT; + } break; + case KEY_P: { + remap_key = KEY_UP; + } break; + case KEY_N: { + remap_key = KEY_DOWN; + } break; + case KEY_D: { + remap_key = KEY_DELETE; + } break; + case KEY_H: { + remap_key = KEY_BACKSPACE; + } break; + } + + if (remap_key != KEY_UNKNOWN) { + k->set_scancode(remap_key); + k->set_control(false); + } + } +#endif + unsigned int code = k->get_scancode(); if (k->get_command()) { @@ -506,7 +539,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (handled) { accept_event(); - } else if (!k->get_alt() && !k->get_command()) { + } else if (!k->get_command()) { if (k->get_unicode() >= 32 && k->get_scancode() != KEY_DELETE) { if (editable) { @@ -890,7 +923,8 @@ void LineEdit::cut_text() { void LineEdit::paste_text() { - String paste_buffer = OS::get_singleton()->get_clipboard(); + // Strip escape characters like \n and \t as they can't be displayed on LineEdit. + String paste_buffer = OS::get_singleton()->get_clipboard().strip_escapes(); if (paste_buffer != "") { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 694065497a..7027fceb84 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -354,6 +354,7 @@ OptionButton::OptionButton() { add_child(popup); popup->set_pass_on_modal_close_click(false); popup->set_notify_transform(true); + popup->set_allow_search(true); popup->connect("id_pressed", this, "_selected"); popup->connect("id_focused", this, "_focused"); popup->connect("popup_hide", this, "set_pressed", varray(false)); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index b7601bdd3e..fdb1b65f77 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -115,6 +115,18 @@ void Popup::set_as_minsize() { set_size(total_minsize); } +void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) { + + Size2 popup_size = p_size; + Size2 window_size = get_viewport_rect().size; + + // clamp popup size in each dimension if window size is too small (using fallback ratio) + popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x); + popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y); + + popup_centered(popup_size); +} + void Popup::popup_centered_minsize(const Size2 &p_minsize) { set_custom_minimum_size(p_minsize); @@ -179,6 +191,7 @@ void Popup::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2())); ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2())); + ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2())); ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive); ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 7ccefe1d75..6615c51ec5 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -64,6 +64,7 @@ public: void popup_centered(const Size2 &p_size = Size2()); void popup_centered_minsize(const Size2 &p_minsize = Size2()); void set_as_minsize(); + void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75); virtual void popup(const Rect2 &p_bounds = Rect2()); virtual String get_configuration_warning() const; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 984307530d..2cac345dae 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -31,6 +31,7 @@ #include "popup_menu.h" #include "core/os/input.h" #include "core/os/keyboard.h" +#include "core/os/os.h" #include "core/print_string.h" #include "core/translation.h" @@ -380,6 +381,43 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); } } + + Ref<InputEventKey> k = p_event; + + if (allow_search && k.is_valid() && k->get_unicode()) { + + uint64_t now = OS::get_singleton()->get_ticks_msec(); + uint64_t diff = now - search_time_msec; + uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000)); + search_time_msec = now; + + if (diff > max_interval) { + search_string = ""; + } + + if (String::chr(k->get_unicode()) != search_string) + search_string += String::chr(k->get_unicode()); + + for (int i = mouse_over + 1; i <= items.size(); i++) { + if (i == items.size()) { + if (mouse_over <= 0) + break; + else + i = 0; + } + + if (i == mouse_over) + break; + + if (items[i].text.findn(search_string) == 0) { + mouse_over = i; + emit_signal("id_focused", i); + update(); + accept_event(); + break; + } + } + } } bool PopupMenu::has_point(const Point2 &p_point) const { @@ -1289,6 +1327,16 @@ float PopupMenu::get_submenu_popup_delay() const { return submenu_timer->get_wait_time(); } +void PopupMenu::set_allow_search(bool p_allow) { + + allow_search = p_allow; +} + +bool PopupMenu::get_allow_search() const { + + return allow_search; +} + void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) { hide_on_window_lose_focus = p_enabled; @@ -1407,6 +1455,9 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus); ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus); + ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search); + ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search); + ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); @@ -1414,6 +1465,7 @@ void PopupMenu::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_search"), "set_allow_search", "get_allow_search"); ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id"))); @@ -1435,6 +1487,10 @@ PopupMenu::PopupMenu() { initial_button_mask = 0; during_grabbed_click = false; + allow_search = false; + search_time_msec = 0; + search_string = ""; + set_focus_mode(FOCUS_ALL); set_as_toplevel(true); set_hide_on_item_selection(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 687006d58d..babdd21281 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -112,6 +112,10 @@ class PopupMenu : public Popup { void _ref_shortcut(Ref<ShortCut> p_sc); void _unref_shortcut(Ref<ShortCut> p_sc); + bool allow_search; + uint64_t search_time_msec; + String search_string; + protected: virtual bool has_point(const Point2 &p_point) const; @@ -206,6 +210,9 @@ public: void set_submenu_popup_delay(float p_time); float get_submenu_popup_delay() const; + void set_allow_search(bool p_allow); + bool get_allow_search() const; + virtual void popup(const Rect2 &p_bounds = Rect2()); void set_hide_on_window_lose_focus(bool p_enabled); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 101eb2ac88..c6b6d29384 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -592,7 +592,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & //assign actual widths for (int i = 0; i < table->columns.size(); i++) { table->columns.write[i].width = table->columns[i].min_width; - if (table->columns[i].expand) + if (table->columns[i].expand && total_ratio > 0) table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; table->total_width += table->columns[i].width + hseparation; } @@ -2336,6 +2336,7 @@ RichTextLabel::RichTextLabel() { tab_size = 4; default_align = ALIGN_LEFT; underline_meta = true; + meta_hovering = NULL; override_selected_font_color = false; scroll_visible = false; diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 2938654ed9..686d1c96cc 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -53,29 +53,19 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (b.is_valid()) { accept_event(); - if (b->get_button_index() == 5 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) { - /* - if (orientation==VERTICAL) - set_val( get_val() + get_page() / 4.0 ); - else - */ set_value(get_value() + get_page() / 4.0); accept_event(); } - if (b->get_button_index() == 4 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) { - /* - if (orientation==HORIZONTAL) - set_val( get_val() - get_page() / 4.0 ); - else - */ set_value(get_value() - get_page() / 4.0); accept_event(); } - if (b->get_button_index() != 1) + if (b->get_button_index() != BUTTON_LEFT) return; if (b->is_pressed()) { diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index e50a71b0ff..a1034937b5 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -88,13 +88,16 @@ void ScrollContainer::_cancel_drag() { void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible_in_tree()) { v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor()); @@ -103,7 +106,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible()) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor()); @@ -122,6 +125,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + if (!OS::get_singleton()->has_touchscreen_ui_hint()) return; @@ -204,6 +210,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); } } + + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed } void ScrollContainer::_update_scrollbar_position() { diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 028ca41cbf..b777e77bc3 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -295,6 +295,7 @@ Slider::Slider(Orientation p_orientation) { mouse_inside = false; grab.active = false; ticks = 0; + ticks_on_borders = false; custom_step = -1; editable = true; scrollable = true; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index d21143739c..e778af3ceb 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -277,6 +277,7 @@ SpinBox::SpinBox() { add_child(line_edit); line_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE); + line_edit->set_mouse_filter(MOUSE_FILTER_PASS); //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered", this, "_text_entered", Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", this, "_line_edit_focus_exit", Vector<Variant>(), CONNECT_DEFERRED); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 380b670368..6b40ecfc6b 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -50,7 +50,7 @@ inline bool _is_symbol(CharType c) { static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return !is_symbol(c); } static bool _is_whitespace(CharType c) { @@ -104,6 +104,13 @@ static CharType _get_right_pair_symbol(CharType c) { return 0; } +static int _find_first_non_whitespace_column_of_line(const String &line) { + int left = 0; + while (left < line.length() && _is_whitespace(line[left])) + left++; + return left; +} + void TextEdit::Text::set_font(const Ref<Font> &p_font) { font = p_font; @@ -399,6 +406,7 @@ void TextEdit::_update_scrollbars() { cursor.line_ofs = 0; cursor.wrap_ofs = 0; v_scroll->set_value(0); + v_scroll->set_max(0); v_scroll->hide(); } @@ -417,6 +425,7 @@ void TextEdit::_update_scrollbars() { cursor.x_ofs = 0; h_scroll->set_value(0); + h_scroll->set_max(0); h_scroll->hide(); } @@ -1106,7 +1115,7 @@ void TextEdit::_notification(int p_what) { if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { // draw the wrap indent offset highlight if (line_wrap_index != 0 && j == 0) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color); } // if its the last char draw to end of the line if (j == str.length() - 1) { @@ -1645,31 +1654,25 @@ void TextEdit::backspace_at_cursor() { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { // handle space indentation - if (cursor.column - indent_size >= 0 && indent_using_spaces) { - - // if there is enough spaces to count as a tab + if (cursor.column != 0 && indent_using_spaces) { + // check if there are no other chars before cursor, just indentation bool unindent = true; - for (int i = 1; i <= indent_size; i++) { - if (text[cursor.line][cursor.column - i] != ' ') { - unindent = false; - break; - } - } - - // and it is before the first character int i = 0; while (i < cursor.column && i < text[cursor.line].length()) { - if (text[cursor.line][i] != ' ' && text[cursor.line][i] != '\t') { + if (!_is_whitespace(text[cursor.line][i])) { unindent = false; break; } i++; } - // then we can remove it as a single character. + // then we can remove all spaces as a single character. if (unindent) { - _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column); - prev_column = cursor.column - indent_size; + // we want to remove spaces up to closest indent + // or whole indent if cursor is pointing at it + int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); + prev_column = cursor.column - spaces_to_delete; + _remove_text(cursor.line, prev_column, cursor.line, cursor.column); } else { _remove_text(prev_line, prev_column, cursor.line, cursor.column); } @@ -1686,6 +1689,10 @@ void TextEdit::indent_right() { int start_line; int end_line; + + // this value informs us by how much we changed selection position by indenting right + // default is 1 for tab indentation + int selection_offset = 1; begin_complex_operation(); if (is_selection_active()) { @@ -1704,18 +1711,24 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); if (indent_using_spaces) { - line_text = space_indent + line_text; + // we don't really care where selection is - we just need to know indentation level at the beginning of the line + int left = _find_first_non_whitespace_column_of_line(line_text); + int spaces_to_add = _calculate_spaces_till_next_right_indent(left); + // since we will add this much spaces we want move whole selection and cursor by this much + selection_offset = spaces_to_add; + for (int j = 0; j < spaces_to_add; j++) + line_text = ' ' + line_text; } else { line_text = '\t' + line_text; } set_line(i, line_text); } - // fix selection and cursor being off by one on the last line + // fix selection and cursor being off after shifting selection right if (is_selection_active()) { - select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); + select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); } - cursor_set_column(cursor.column + 1, false); + cursor_set_column(cursor.column + selection_offset, false); end_complex_operation(); update(); } @@ -1724,6 +1737,15 @@ void TextEdit::indent_left() { int start_line; int end_line; + + // moving cursor and selection after unindenting can get tricky + // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either) + // therefore we just remember initial values + // and at the end of the operation offset them by number of removed characters + int removed_characters = 0; + int initial_selection_end_column = selection.to_column; + int initial_cursor_column = cursor.column; + begin_complex_operation(); if (is_selection_active()) { @@ -1746,21 +1768,43 @@ void TextEdit::indent_left() { if (line_text.begins_with("\t")) { line_text = line_text.substr(1, line_text.length()); set_line(i, line_text); - } else if (line_text.begins_with(space_indent)) { - line_text = line_text.substr(indent_size, line_text.length()); + removed_characters = 1; + } else if (line_text.begins_with(" ")) { + // when unindenting we aim to remove spaces before line that has selection no matter what is selected + // so we start of by finding first non whitespace character of line + int left = _find_first_non_whitespace_column_of_line(line_text); + + // here we remove only enough spaces to align text to nearest full multiple of indentation_size + // in case where selection begins at the start of indentation_size multiple we remove whole indentation level + int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); + + line_text = line_text.substr(spaces_to_remove, line_text.length()); set_line(i, line_text); + removed_characters = spaces_to_remove; } } // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); + select(selection.from_line, selection.from_column - removed_characters, + selection.to_line, initial_selection_end_column - removed_characters); } - cursor_set_column(cursor.column - 1, false); + cursor_set_column(initial_cursor_column - removed_characters, false); end_complex_operation(); update(); } +int TextEdit::_calculate_spaces_till_next_left_indent(int column) { + int spaces_till_indent = column % indent_size; + if (spaces_till_indent == 0) + spaces_till_indent = indent_size; + return spaces_till_indent; +} + +int TextEdit::_calculate_spaces_till_next_right_indent(int column) { + return indent_size - column % indent_size; +} + void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const { float rows = p_mouse.y; @@ -1812,6 +1856,9 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { @@ -2066,6 +2113,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _scroll_down(delta); } h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100); + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + return; } @@ -2109,6 +2159,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + Ref<InputEventKey> k = p_gui_input; if (k.is_valid()) { @@ -2517,15 +2570,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (k->get_shift()) { - //simple unindent + // simple unindent int cc = cursor.column; - - const int len = text[cursor.line].length(); const String &line = text[cursor.line]; - int left = 0; // number of whitespace chars at beginning of line - while (left < len && (line[left] == '\t' || line[left] == ' ')) - left++; + int left = _find_first_non_whitespace_column_of_line(line); cc = MIN(cc, left); while (cc < indent_size && cc < left && line[cc] == ' ') @@ -2533,24 +2582,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc > 0 && cc <= text[cursor.line].length()) { if (text[cursor.line][cc - 1] == '\t') { + // tabs unindentation _remove_text(cursor.line, cc - 1, cursor.line, cc); if (cursor.column >= left) cursor_set_column(MAX(0, cursor.column - 1)); update(); } else { - int n = 0; - - for (int i = 1; i <= MIN(cc, indent_size); i++) { - if (line[cc - i] != ' ') { - break; - } - n++; - } - - if (n > 0) { - _remove_text(cursor.line, cc - n, cursor.line, cc); - if (cursor.column > left - n) // inside text? - cursor_set_column(MAX(0, cursor.column - n)); + // spaces unindentation + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); + if (cursor.column > left - spaces_to_remove) // inside text? + cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); update(); } } @@ -2559,9 +2602,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } } else { - //simple indent + // simple indent if (indent_using_spaces) { - _insert_text_at_cursor(space_indent); + // insert only as much spaces as needed till next indentation level + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); + String indent_to_insert = String(); + for (int i = 0; i < spaces_to_add; i++) + indent_to_insert = ' ' + indent_to_insert; + _insert_text_at_cursor(indent_to_insert); } else { _insert_text_at_cursor("\t"); } @@ -4121,7 +4169,7 @@ void TextEdit::_scroll_moved(double p_to_val) { int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; - for (n_line = 0; n_line < text.size(); n_line++) { + for (n_line = 0; n_line < text.size() - 1; n_line++) { if (!is_line_hidden(n_line)) { sc++; sc += times_line_wraps(n_line); @@ -4634,6 +4682,8 @@ bool TextEdit::has_keyword_color(String p_keyword) const { } Color TextEdit::get_keyword_color(String p_keyword) const { + + ERR_FAIL_COND_V(!keywords.has(p_keyword), Color()); return keywords[p_keyword]; } @@ -6294,14 +6344,14 @@ int TextEdit::get_info_gutter_width() const { return info_gutter_width; } -void TextEdit::set_hiding_enabled(int p_enabled) { +void TextEdit::set_hiding_enabled(bool p_enabled) { if (!p_enabled) unhide_all_lines(); hiding_enabled = p_enabled; update(); } -int TextEdit::is_hiding_enabled() const { +bool TextEdit::is_hiding_enabled() const { return hiding_enabled; } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 64cbafc717..0c26602d2b 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -437,6 +437,9 @@ private: void _confirm_completion(); void _update_completion_candidates(); + int _calculate_spaces_till_next_left_indent(int column); + int _calculate_spaces_till_next_right_indent(int column); + protected: virtual String get_tooltip(const Point2 &p_pos) const; @@ -694,8 +697,8 @@ public: void set_info_gutter_width(int p_gutter_width); int get_info_gutter_width() const; - void set_hiding_enabled(int p_enabled); - int is_hiding_enabled() const; + void set_hiding_enabled(bool p_enabled); + bool is_hiding_enabled() const; void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 049cae9dd9..522c1ecb6a 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -39,7 +39,7 @@ #include "scene/main/viewport.h" #ifdef TOOLS_ENABLED -#include "editor/editor_node.h" +#include "editor/editor_scale.h" #endif #include <limits.h> @@ -318,7 +318,7 @@ void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName void TreeItem::set_collapsed(bool p_collapsed) { - if (collapsed == p_collapsed) + if (collapsed == p_collapsed || !tree) return; collapsed = p_collapsed; TreeItem *ci = tree->selected_item; @@ -344,8 +344,7 @@ void TreeItem::set_collapsed(bool p_collapsed) { } _changed_notify(); - if (tree) - tree->emit_signal("item_collapsed", this); + tree->emit_signal("item_collapsed", this); } bool TreeItem::is_collapsed() { @@ -389,7 +388,7 @@ TreeItem *TreeItem::get_children() { return children; } -TreeItem *TreeItem::get_prev_visible() { +TreeItem *TreeItem::get_prev_visible(bool p_wrap) { TreeItem *current = this; @@ -398,8 +397,20 @@ TreeItem *TreeItem::get_prev_visible() { if (!prev) { current = current->parent; - if (!current || (current == tree->root && tree->hide_root)) + if (current == tree->root && tree->hide_root) { return NULL; + } else if (!current) { + if (p_wrap) { + current = this; + TreeItem *temp = this->get_next_visible(); + while (temp) { + current = temp; + temp = temp->get_next_visible(); + } + } else { + return NULL; + } + } } else { current = prev; @@ -415,7 +426,7 @@ TreeItem *TreeItem::get_prev_visible() { return current; } -TreeItem *TreeItem::get_next_visible() { +TreeItem *TreeItem::get_next_visible(bool p_wrap) { TreeItem *current = this; @@ -433,10 +444,14 @@ TreeItem *TreeItem::get_next_visible() { current = current->parent; } - if (current == NULL) - return NULL; - else + if (!current) { + if (p_wrap) + return tree->root; + else + return NULL; + } else { current = current->next; + } } return current; @@ -740,8 +755,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent); ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children); - ClassDB::bind_method(D_METHOD("get_next_visible"), &TreeItem::get_next_visible); - ClassDB::bind_method(D_METHOD("get_prev_visible"), &TreeItem::get_prev_visible); + 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)); ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child); @@ -1970,6 +1985,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool item_h += child_h; } } + if (p_item == root && p_button == BUTTON_RIGHT) { + emit_signal("empty_rmb", get_local_mouse_position()); + } } return item_h; // nothing found @@ -3488,6 +3506,7 @@ void Tree::scroll_to_item(TreeItem *p_item) { TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards) { + TreeItem *from = p_at; while (p_at) { for (int i = 0; i < columns.size(); i++) { @@ -3499,9 +3518,12 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c } if (p_backwards) - p_at = p_at->get_prev_visible(); + p_at = p_at->get_prev_visible(true); else - p_at = p_at->get_next_visible(); + p_at = p_at->get_next_visible(true); + + if ((p_at) == from) + break; } return NULL; @@ -3509,10 +3531,14 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_selectable) { - if (!root) + TreeItem *from = get_selected(); + + if (!from) + from = root; + if (!from) return NULL; - return _search_item_text(root, p_find, r_col, p_selectable); + return _search_item_text(from->get_next_visible(true), p_find, r_col, p_selectable); } void Tree::_do_incr_search(const String &p_add) { @@ -3521,7 +3547,7 @@ void Tree::_do_incr_search(const String &p_add) { uint64_t diff = time - last_keypress; if (diff > uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000))) incr_search = p_add; - else + else if (incr_search != p_add) incr_search += p_add; last_keypress = time; @@ -3694,6 +3720,10 @@ String Tree::get_tooltip(const Point2 &p_pos) const { 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<Texture> b = c.buttons[j].texture; Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); @@ -3853,6 +3883,7 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("cell_selected")); ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected"))); ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); + ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("item_edited")); ADD_SIGNAL(MethodInfo("item_rmb_edited")); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 26d64baafb..45d451eb72 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -238,8 +238,8 @@ public: TreeItem *get_parent(); TreeItem *get_children(); - TreeItem *get_prev_visible(); - TreeItem *get_next_visible(); + TreeItem *get_prev_visible(bool p_wrap = false); + TreeItem *get_next_visible(bool p_wrap = false); void remove_child(TreeItem *p_item); |