diff options
Diffstat (limited to 'scene/gui')
-rw-r--r-- | scene/gui/control.cpp | 2 | ||||
-rw-r--r-- | scene/gui/dialogs.cpp | 15 | ||||
-rw-r--r-- | scene/gui/dialogs.h | 14 | ||||
-rw-r--r-- | scene/gui/file_dialog.h | 50 | ||||
-rw-r--r-- | scene/gui/gradient_edit.h | 4 | ||||
-rw-r--r-- | scene/gui/graph_edit.h | 32 | ||||
-rw-r--r-- | scene/gui/item_list.h | 2 | ||||
-rw-r--r-- | scene/gui/menu_button.h | 2 | ||||
-rw-r--r-- | scene/gui/option_button.h | 2 | ||||
-rw-r--r-- | scene/gui/popup.h | 2 | ||||
-rw-r--r-- | scene/gui/popup_menu.h | 8 | ||||
-rw-r--r-- | scene/gui/range.h | 2 | ||||
-rw-r--r-- | scene/gui/rich_text_label.cpp | 29 | ||||
-rw-r--r-- | scene/gui/rich_text_label.h | 1 | ||||
-rw-r--r-- | scene/gui/scroll_container.h | 4 | ||||
-rw-r--r-- | scene/gui/spin_box.h | 4 | ||||
-rw-r--r-- | scene/gui/tab_container.cpp | 19 | ||||
-rw-r--r-- | scene/gui/tab_container.h | 6 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 69 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 10 | ||||
-rw-r--r-- | scene/gui/tree.h | 14 | ||||
-rw-r--r-- | scene/gui/view_panner.cpp | 2 |
22 files changed, 178 insertions, 115 deletions
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2f96ee675f..96d2b29fc1 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -367,7 +367,7 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const { void Control::_get_property_list(List<PropertyInfo> *p_list) const { Ref<Theme> theme = Theme::get_default(); - p_list->push_back(PropertyInfo(Variant::NIL, "Theme Overrides", PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); { List<StringName> names; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index be57ca9084..0bb96a18a5 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -39,13 +39,13 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) { Ref<InputEventKey> key = p_event; - if (key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ESCAPE) { + if (close_on_escape && key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ESCAPE) { _cancel_pressed(); } } void AcceptDialog::_parent_focused() { - if (!is_exclusive()) { + if (close_on_escape && !is_exclusive()) { _cancel_pressed(); } } @@ -145,6 +145,14 @@ bool AcceptDialog::get_hide_on_ok() const { return hide_on_ok; } +void AcceptDialog::set_close_on_escape(bool p_hide) { + close_on_escape = p_hide; +} + +bool AcceptDialog::get_close_on_escape() const { + return close_on_escape; +} + void AcceptDialog::set_autowrap(bool p_autowrap) { label->set_autowrap_mode(p_autowrap ? Label::AUTOWRAP_WORD : Label::AUTOWRAP_OFF); } @@ -288,6 +296,8 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_label"), &AcceptDialog::get_label); ClassDB::bind_method(D_METHOD("set_hide_on_ok", "enabled"), &AcceptDialog::set_hide_on_ok); ClassDB::bind_method(D_METHOD("get_hide_on_ok"), &AcceptDialog::get_hide_on_ok); + ClassDB::bind_method(D_METHOD("set_close_on_escape", "enabled"), &AcceptDialog::set_close_on_escape); + ClassDB::bind_method(D_METHOD("get_close_on_escape"), &AcceptDialog::get_close_on_escape); ClassDB::bind_method(D_METHOD("add_button", "text", "right", "action"), &AcceptDialog::add_button, DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("add_cancel_button", "name"), &AcceptDialog::add_cancel_button); ClassDB::bind_method(D_METHOD("remove_button", "button"), &AcceptDialog::remove_button); @@ -304,6 +314,7 @@ void AcceptDialog::_bind_methods() { ADD_GROUP("Dialog", "dialog"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_close_on_escape"), "set_close_on_escape", "get_close_on_escape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_autowrap"), "set_autowrap", "has_autowrap"); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 1365b1df24..41fd9c0a10 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -45,11 +45,12 @@ class AcceptDialog : public Window { GDCLASS(AcceptDialog, Window); Window *parent_visible = nullptr; - Panel *bg; - HBoxContainer *hbc; - Label *label; - Button *ok; + Panel *bg = nullptr; + HBoxContainer *hbc = nullptr; + Label *label = nullptr; + Button *ok = nullptr; bool hide_on_ok = true; + bool close_on_escape = true; void _custom_action(const String &p_action); void _update_child_rects(); @@ -87,6 +88,9 @@ public: void set_hide_on_ok(bool p_hide); bool get_hide_on_ok() const; + void set_close_on_escape(bool p_enable); + bool get_close_on_escape() const; + void set_text(String p_text); String get_text() const; @@ -99,7 +103,7 @@ public: class ConfirmationDialog : public AcceptDialog { GDCLASS(ConfirmationDialog, AcceptDialog); - Button *cancel; + Button *cancel = nullptr; protected: static void _bind_methods(); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 7a50efe40f..9bba93bb89 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -65,34 +65,34 @@ public: static RegisterFunc unregister_func; private: - ConfirmationDialog *makedialog; - LineEdit *makedirname; + ConfirmationDialog *makedialog = nullptr; + LineEdit *makedirname = nullptr; - Button *makedir; + Button *makedir = nullptr; Access access = ACCESS_RESOURCES; - VBoxContainer *vbox; + VBoxContainer *vbox = nullptr; FileMode mode; - LineEdit *dir; - HBoxContainer *drives_container; - HBoxContainer *shortcuts_container; - OptionButton *drives; - Tree *tree; - HBoxContainer *file_box; - LineEdit *file; - OptionButton *filter; - AcceptDialog *mkdirerr; - AcceptDialog *exterr; - DirAccess *dir_access; - ConfirmationDialog *confirm_save; - - Label *message; - - Button *dir_prev; - Button *dir_next; - Button *dir_up; - - Button *refresh; - Button *show_hidden; + LineEdit *dir = nullptr; + HBoxContainer *drives_container = nullptr; + HBoxContainer *shortcuts_container = nullptr; + OptionButton *drives = nullptr; + Tree *tree = nullptr; + HBoxContainer *file_box = nullptr; + LineEdit *file = nullptr; + OptionButton *filter = nullptr; + AcceptDialog *mkdirerr = nullptr; + AcceptDialog *exterr = nullptr; + DirAccess *dir_access = nullptr; + ConfirmationDialog *confirm_save = nullptr; + + Label *message = nullptr; + + Button *dir_prev = nullptr; + Button *dir_next = nullptr; + Button *dir_up = nullptr; + + Button *refresh = nullptr; + Button *show_hidden = nullptr; Vector<String> filters; diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index 67531d4f4a..4e3c6525f9 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -38,8 +38,8 @@ class GradientEdit : public Control { GDCLASS(GradientEdit, Control); - PopupPanel *popup; - ColorPicker *picker; + PopupPanel *popup = nullptr; + ColorPicker *picker = nullptr; bool grabbing = false; int grabbed = -1; diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index b0d1944d6e..18b9eeebd4 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -46,7 +46,7 @@ class GraphEditFilter : public Control { friend class GraphEdit; friend class GraphEditMinimap; - GraphEdit *ge; + GraphEdit *ge = nullptr; virtual bool has_point(const Point2 &p_point) const override; public: @@ -58,7 +58,7 @@ class GraphEditMinimap : public Control { friend class GraphEdit; friend class GraphEditFilter; - GraphEdit *ge; + GraphEdit *ge = nullptr; protected: public: @@ -109,20 +109,20 @@ public: }; private: - Label *zoom_label; - Button *zoom_minus; - Button *zoom_reset; - Button *zoom_plus; + Label *zoom_label = nullptr; + Button *zoom_minus = nullptr; + Button *zoom_reset = nullptr; + Button *zoom_plus = nullptr; - Button *snap_button; - SpinBox *snap_amount; + Button *snap_button = nullptr; + SpinBox *snap_amount = nullptr; - Button *minimap_button; + Button *minimap_button = nullptr; - Button *layout_button; + Button *layout_button = nullptr; - HScrollBar *h_scroll; - VScrollBar *v_scroll; + HScrollBar *h_scroll = nullptr; + VScrollBar *v_scroll = nullptr; float port_grab_distance_horizontal = 0.0; float port_grab_distance_vertical; @@ -190,9 +190,9 @@ private: void _scroll_moved(double); virtual void gui_input(const Ref<InputEvent> &p_ev) override; - Control *connections_layer; - GraphEditFilter *top_layer; - GraphEditMinimap *minimap; + Control *connections_layer = nullptr; + GraphEditFilter *top_layer = nullptr; + GraphEditMinimap *minimap = nullptr; void _top_layer_input(const Ref<InputEvent> &p_ev); bool is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size); @@ -236,7 +236,7 @@ private: void _set_drag_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, bool p_drag); void _set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, Vector2 p_pos); - HBoxContainer *zoom_hb; + HBoxContainer *zoom_hb = nullptr; friend class GraphEditFilter; bool _filter_input(const Point2 &p_point); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 96735678c1..ffbe7d055a 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -98,7 +98,7 @@ private: SelectMode select_mode = SELECT_SINGLE; IconMode icon_mode = ICON_MODE_LEFT; - VScrollBar *scroll_bar; + VScrollBar *scroll_bar = nullptr; TextParagraph::OverrunBehavior text_overrun_behavior = TextParagraph::OVERRUN_TRIM_ELLIPSIS; uint64_t search_time_msec = 0; diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 9cfb780255..e3ead9c291 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -40,7 +40,7 @@ class MenuButton : public Button { bool clicked = false; bool switch_on_hover = false; bool disable_shortcuts = false; - PopupMenu *popup; + PopupMenu *popup = nullptr; Vector2i mouse_pos_adjusted; diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 732730e0f4..921b76c52a 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -37,7 +37,7 @@ class OptionButton : public Button { GDCLASS(OptionButton, Button); - PopupMenu *popup; + PopupMenu *popup = nullptr; int current = -1; void _focused(int p_which); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index c45f4ddc24..6211af4d20 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -65,7 +65,7 @@ public: class PopupPanel : public Popup { GDCLASS(PopupPanel, Popup); - Panel *panel; + Panel *panel = nullptr; protected: void _update_child_rects(); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 5ce55209d4..518ba14dae 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -89,7 +89,7 @@ class PopupMenu : public Popup { bool close_allowed = false; Timer *minimum_lifetime_timer = nullptr; - Timer *submenu_timer; + Timer *submenu_timer = nullptr; List<Rect2> autohide_areas; Vector<Item> items; MouseButton initial_button_mask = MouseButton::NONE; @@ -125,9 +125,9 @@ class PopupMenu : public Popup { uint64_t search_time_msec = 0; String search_string = ""; - MarginContainer *margin_container; - ScrollContainer *scroll_container; - Control *control; + MarginContainer *margin_container = nullptr; + ScrollContainer *scroll_container = nullptr; + Control *control = nullptr; void _draw_items(); void _draw_background(); diff --git a/scene/gui/range.h b/scene/gui/range.h index 597c50ca26..46b0d39202 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -50,7 +50,7 @@ class Range : public Control { void emit_changed(const char *p_what = ""); }; - Shared *shared; + Shared *shared = nullptr; void _ref_shared(Shared *p_shared); void _unref_shared(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 70755a2870..86f0b37482 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1650,8 +1650,7 @@ void RichTextLabel::_notification(int p_what) { case NOTIFICATION_FOCUS_EXIT: { if (deselect_on_focus_loss_enabled) { - selection.active = false; - update(); + deselect(); } } break; @@ -1742,9 +1741,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { selection.to_line = 0; selection.to_item = nullptr; selection.to_char = 0; - selection.active = false; - - update(); + deselect(); } } } @@ -1802,9 +1799,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { selection.to_line = 0; selection.to_item = nullptr; selection.to_char = 0; - selection.active = false; - - update(); + deselect(); } } @@ -1925,8 +1920,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (selection.from_char > selection.to_char) { swap = true; } else if (selection.from_char == selection.to_char) { - selection.active = false; - update(); + deselect(); return; } } @@ -2977,11 +2971,10 @@ void RichTextLabel::clear() { main->lines.clear(); main->lines.resize(1); main->first_invalid_line = 0; - update(); selection.click_frame = nullptr; selection.click_item = nullptr; - selection.active = false; + deselect(); current_idx = 1; current_char_ofs = 0; @@ -3890,8 +3883,7 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) { selection.enabled = p_enabled; if (!p_enabled) { if (selection.active) { - selection.active = false; - update(); + deselect(); } set_focus_mode(FOCUS_NONE); } else { @@ -3902,8 +3894,7 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) { void RichTextLabel::set_deselect_on_focus_loss_enabled(const bool p_enabled) { deselect_on_focus_loss_enabled = p_enabled; if (p_enabled && selection.active && !has_focus()) { - selection.active = false; - update(); + deselect(); } } @@ -4154,6 +4145,11 @@ String RichTextLabel::get_selected_text() const { return text; } +void RichTextLabel::deselect() { + selection.active = false; + update(); +} + void RichTextLabel::selection_copy() { String text = get_selected_text(); @@ -4460,6 +4456,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_selection_to"), &RichTextLabel::get_selection_to); ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text); + ClassDB::bind_method(D_METHOD("deselect"), &RichTextLabel::deselect); ClassDB::bind_method(D_METHOD("parse_bbcode", "bbcode"), &RichTextLabel::parse_bbcode); ClassDB::bind_method(D_METHOD("append_text", "bbcode"), &RichTextLabel::append_text); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index c9cbbe9d15..ccac1d5ea6 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -587,6 +587,7 @@ public: void selection_copy(); void set_deselect_on_focus_loss_enabled(const bool p_enabled); bool is_deselect_on_focus_loss_enabled() const; + void deselect(); void parse_bbcode(const String &p_bbcode); void append_text(const String &p_bbcode); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index c00df87b18..b9fcf64db6 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -47,8 +47,8 @@ public: }; private: - HScrollBar *h_scroll; - VScrollBar *v_scroll; + HScrollBar *h_scroll = nullptr; + VScrollBar *v_scroll = nullptr; Size2 child_max_size; diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index a15e3fe5f5..d118b28334 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -38,11 +38,11 @@ class SpinBox : public Range { GDCLASS(SpinBox, Range); - LineEdit *line_edit; + LineEdit *line_edit = nullptr; int last_w = 0; bool update_on_text_changed = false; - Timer *range_click_timer; + Timer *range_click_timer = nullptr; void _range_click_timeout(); void _release_mouse(); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 05f1ee3dad..84a62c71c2 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -472,6 +472,10 @@ void TabContainer::_on_tab_selected(int p_tab) { emit_signal(SNAME("tab_selected"), p_tab); } +void TabContainer::_on_tab_button_pressed(int p_tab) { + emit_signal(SNAME("tab_button_pressed"), p_tab); +} + void TabContainer::_refresh_tab_names() { Vector<Control *> controls = _get_tab_controls(); for (int i = 0; i < controls.size(); i++) { @@ -733,6 +737,17 @@ bool TabContainer::is_tab_hidden(int p_tab) const { return tab_bar->is_tab_hidden(p_tab); } +void TabContainer::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) { + tab_bar->set_tab_button_icon(p_tab, p_icon); + + _update_margins(); + _repaint(); +} + +Ref<Texture2D> TabContainer::get_tab_button_icon(int p_tab) const { + return tab_bar->get_tab_button_icon(p_tab); +} + void TabContainer::get_translatable_strings(List<String> *p_strings) const { Vector<Control *> controls = _get_tab_controls(); for (int i = 0; i < controls.size(); i++) { @@ -877,6 +892,8 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabContainer::is_tab_disabled); ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabContainer::set_tab_hidden); ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabContainer::is_tab_hidden); + ClassDB::bind_method(D_METHOD("set_tab_button_icon", "tab_idx", "icon"), &TabContainer::set_tab_button_icon); + ClassDB::bind_method(D_METHOD("get_tab_button_icon", "tab_idx"), &TabContainer::get_tab_button_icon); ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point); ClassDB::bind_method(D_METHOD("get_tab_idx_from_control", "control"), &TabContainer::get_tab_idx_from_control); ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup); @@ -896,6 +913,7 @@ void TabContainer::_bind_methods() { ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_button_pressed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("pre_popup_pressed")); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); @@ -915,6 +933,7 @@ TabContainer::TabContainer() { tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE); tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed)); tab_bar->connect("tab_selected", callable_mp(this, &TabContainer::_on_tab_selected)); + tab_bar->connect("tab_button_pressed", callable_mp(this, &TabContainer::_on_tab_button_pressed)); connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited)); } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index c54934b37b..9adaa0d844 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -38,7 +38,7 @@ class TabContainer : public Container { GDCLASS(TabContainer, Container); - TabBar *tab_bar; + TabBar *tab_bar = nullptr; bool tabs_visible = true; bool all_tabs_in_front = false; bool menu_hovered = false; @@ -56,6 +56,7 @@ class TabContainer : public Container { void _on_mouse_exited(); void _on_tab_changed(int p_tab); void _on_tab_selected(int p_tab); + void _on_tab_button_pressed(int p_tab); Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control); bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const; @@ -97,6 +98,9 @@ public: void set_tab_hidden(int p_tab, bool p_hidden); bool is_tab_hidden(int p_tab) const; + void set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon); + Ref<Texture2D> get_tab_button_icon(int p_tab) const; + int get_tab_count() const; void set_current_tab(int p_current); int get_current_tab() const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3c80e3f987..1bed72c907 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -471,6 +471,11 @@ void TextEdit::_notification(int p_what) { // To ensure minimap is responsive override the speed setting. double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time(); + // Prevent too small velocity to block scrolling + if (Math::abs(vel) < v_scroll->get_step()) { + vel = v_scroll->get_step() * SIGN(vel); + } + if (Math::abs(vel) >= dist) { set_v_scroll(target_v_scroll); scrolling = false; @@ -2133,16 +2138,21 @@ void TextEdit::_move_caret_left(bool p_select, bool p_move_by_word) { if (p_move_by_word) { int cc = caret.column; - + // If the caret is at the start of the line, and not on the first line, move it up to the end of the previous line. if (cc == 0 && caret.line > 0) { set_caret_line(caret.line - 1); set_caret_column(text[caret.line].length()); } else { PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); - for (int i = words.size() - 2; i >= 0; i = i - 2) { - if (words[i] < cc) { - cc = words[i]; - break; + if (words.is_empty() || cc <= words[0]) { + // This solves the scenario where there are no words but glyfs that can be ignored. + cc = 0; + } else { + for (int i = words.size() - 2; i >= 0; i = i - 2) { + if (words[i] < cc) { + cc = words[i]; + break; + } } } set_caret_column(cc); @@ -2184,16 +2194,21 @@ void TextEdit::_move_caret_right(bool p_select, bool p_move_by_word) { if (p_move_by_word) { int cc = caret.column; - + // If the caret is at the end of the line, and not on the last line, move it down to the beginning of the next line. if (cc == text[caret.line].length() && caret.line < text.size() - 1) { set_caret_line(caret.line + 1); set_caret_column(0); } else { PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); - for (int i = 1; i < words.size(); i = i + 2) { - if (words[i] > cc) { - cc = words[i]; - break; + if (words.is_empty() || cc >= words[words.size() - 1]) { + // This solves the scenario where there are no words but glyfs that can be ignored. + cc = text[caret.line].length(); + } else { + for (int i = 1; i < words.size(); i = i + 2) { + if (words[i] > cc) { + cc = words[i]; + break; + } } } set_caret_column(cc); @@ -2364,11 +2379,11 @@ void TextEdit::_move_caret_page_down(bool p_select) { } void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { - if (!editable) { + if (!editable || (caret.column == 0 && caret.line == 0)) { return; } - if (has_selection() || (!p_all_to_left && !p_word)) { + if (has_selection() || (!p_all_to_left && !p_word) || caret.column == 0) { backspace(); return; } @@ -2381,20 +2396,30 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { } if (p_word) { - int line = caret.line; int column = caret.column; - - PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); - for (int i = words.size() - 2; i >= 0; i = i - 2) { - if (words[i] < column) { - column = words[i]; - break; + // Check for the case "<word><space><caret>" and ignore the space. + // No need to check for column being 0 since it is cheked above. + if (is_whitespace(text[caret.line][caret.column - 1])) { + column -= 1; + } + // Get a list with the indices of the word bounds of the given text line. + const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); + if (words.is_empty() || column <= words[0]) { + // If "words" is empty, meaning no words are left, we can remove everything until the begining of the line. + column = 0; + } else { + // Otherwise search for the first word break that is smaller than the index from we're currentlu deleteing + for (int i = words.size() - 2; i >= 0; i = i - 2) { + if (words[i] < column) { + column = words[i]; + break; + } } } - _remove_text(line, column, caret.line, caret.column); + _remove_text(caret.line, column, caret.line, caret.column); - set_caret_line(line, false); + set_caret_line(caret.line, false); set_caret_column(column); return; } @@ -4390,6 +4415,8 @@ int TextEdit::get_h_scroll() const { } void TextEdit::set_v_scroll_speed(float p_speed) { + // Prevent setting a vertical scroll speed value under 1.0 + ERR_FAIL_COND(p_speed < 1.0); v_scroll_speed = p_speed; } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 6deaf76e5e..7d36051a37 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -325,7 +325,7 @@ private: List<TextOperation> undo_stack; List<TextOperation>::Element *undo_stack_pos = nullptr; - Timer *idle_detect; + Timer *idle_detect = nullptr; uint32_t version = 0; uint32_t saved_version = 0; @@ -380,7 +380,7 @@ private: bool draw_caret = true; bool caret_blink_enabled = false; - Timer *caret_blink_timer; + Timer *caret_blink_timer = nullptr; bool move_caret_on_right_click = true; @@ -426,7 +426,7 @@ private: bool dragging_selection = false; - Timer *click_select_held; + Timer *click_select_held = nullptr; uint64_t last_dblclk = 0; Vector2 last_dblclk_pos; void _click_selection_held(); @@ -449,8 +449,8 @@ private: void _update_caret_wrap_offset(); /* Viewport. */ - HScrollBar *h_scroll; - VScrollBar *v_scroll; + HScrollBar *h_scroll = nullptr; + VScrollBar *v_scroll = nullptr; bool scroll_past_end_of_file_enabled = false; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 04d4b9b935..74ad4f94b8 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -134,7 +134,7 @@ private: Vector<TreeItem *> children_cache; bool is_root = false; // for tree root - Tree *tree; // tree (for reference) + Tree *tree = nullptr; // tree (for reference) TreeItem(Tree *p_tree); @@ -428,18 +428,18 @@ private: bool show_column_titles = false; - VBoxContainer *popup_editor_vb; + VBoxContainer *popup_editor_vb = nullptr; - Popup *popup_editor; + Popup *popup_editor = nullptr; LineEdit *text_editor = nullptr; - HSlider *value_editor; + HSlider *value_editor = nullptr; bool updating_value_editor = false; uint64_t focus_in_id = 0; PopupMenu *popup_menu = nullptr; Vector<ColumnInfo> columns; - Timer *range_click_timer; + Timer *range_click_timer = nullptr; TreeItem *range_item_last = nullptr; bool range_up_last = false; void _range_click_timeout(); @@ -553,8 +553,8 @@ private: int _get_title_button_height() const; void _scroll_moved(float p_value); - HScrollBar *h_scroll; - VScrollBar *v_scroll; + HScrollBar *h_scroll = nullptr; + VScrollBar *v_scroll = nullptr; bool h_scroll_enabled = true; bool v_scroll_enabled = true; diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp index 71865b4864..892d0aba29 100644 --- a/scene/gui/view_panner.cpp +++ b/scene/gui/view_panner.cpp @@ -37,7 +37,7 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - Vector2i scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP)); + Vector2 scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP)); if (scroll_vec != Vector2()) { if (control_scheme == SCROLL_PANS) { if (mb->is_ctrl_pressed()) { |