summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp4
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/code_edit.cpp32
-rw-r--r--scene/gui/code_edit.h8
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/container.cpp2
-rw-r--r--scene/gui/control.cpp10
-rw-r--r--scene/gui/control.h3
-rw-r--r--scene/gui/dialogs.cpp18
-rw-r--r--scene/gui/dialogs.h14
-rw-r--r--scene/gui/file_dialog.cpp6
-rw-r--r--scene/gui/file_dialog.h52
-rw-r--r--scene/gui/flow_container.cpp9
-rw-r--r--scene/gui/gradient_edit.h4
-rw-r--r--scene/gui/graph_edit.h32
-rw-r--r--scene/gui/item_list.h2
-rw-r--r--scene/gui/label.cpp6
-rw-r--r--scene/gui/line_edit.cpp24
-rw-r--r--scene/gui/line_edit.h1
-rw-r--r--scene/gui/menu_button.cpp4
-rw-r--r--scene/gui/menu_button.h4
-rw-r--r--scene/gui/option_button.cpp16
-rw-r--r--scene/gui/option_button.h5
-rw-r--r--scene/gui/popup.h2
-rw-r--r--scene/gui/popup_menu.cpp4
-rw-r--r--scene/gui/popup_menu.h8
-rw-r--r--scene/gui/progress_bar.cpp2
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_label.cpp301
-rw-r--r--scene/gui/rich_text_label.h16
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/scroll_container.h4
-rw-r--r--scene/gui/spin_box.h4
-rw-r--r--scene/gui/subviewport_container.cpp21
-rw-r--r--scene/gui/subviewport_container.h2
-rw-r--r--scene/gui/tab_bar.cpp102
-rw-r--r--scene/gui/tab_bar.h3
-rw-r--r--scene/gui/tab_container.cpp76
-rw-r--r--scene/gui/tab_container.h6
-rw-r--r--scene/gui/text_edit.cpp92
-rw-r--r--scene/gui/text_edit.h11
-rw-r--r--scene/gui/texture_progress_bar.cpp18
-rw-r--r--scene/gui/tree.cpp7
-rw-r--r--scene/gui/tree.h16
-rw-r--r--scene/gui/video_stream_player.cpp4
-rw-r--r--scene/gui/view_panner.cpp2
47 files changed, 702 insertions, 267 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index ab86face7e..789c01adf3 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -339,14 +339,14 @@ bool BaseButton::is_keep_pressed_outside() const {
void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) {
shortcut = p_shortcut;
- set_process_unhandled_key_input(shortcut.is_valid());
+ set_process_shortcut_input(shortcut.is_valid());
}
Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
-void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
+void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shortcut_context()) {
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index a2b6ee0845..f4f9b88868 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -77,7 +77,7 @@ protected:
virtual void toggled(bool p_pressed);
static void _bind_methods();
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
bool _is_focus_owner_in_shortcut_context() const;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 3fa0cec302..2e87e71972 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1782,10 +1782,10 @@ void CodeEdit::request_code_completion(bool p_force) {
/* Don't re-query if all existing options are quoted types, eg path, signal. */
bool ignored = code_completion_active && !code_completion_options.is_empty();
if (ignored) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT;
- const ScriptCodeCompletionOption *previous_option = nullptr;
+ ScriptLanguage::CodeCompletionKind kind = ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT;
+ const ScriptLanguage::CodeCompletionOption *previous_option = nullptr;
for (int i = 0; i < code_completion_options.size(); i++) {
- const ScriptCodeCompletionOption &current_option = code_completion_options[i];
+ const ScriptLanguage::CodeCompletionOption &current_option = code_completion_options[i];
if (!previous_option) {
previous_option = &current_option;
kind = current_option.kind;
@@ -1795,7 +1795,7 @@ void CodeEdit::request_code_completion(bool p_force) {
break;
}
}
- ignored = ignored && (kind == ScriptCodeCompletionOption::KIND_FILE_PATH || kind == ScriptCodeCompletionOption::KIND_NODE_PATH || kind == ScriptCodeCompletionOption::KIND_SIGNAL);
+ ignored = ignored && (kind == ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH || kind == ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH || kind == ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
}
if (ignored) {
@@ -1818,8 +1818,8 @@ void CodeEdit::request_code_completion(bool p_force) {
}
void CodeEdit::add_code_completion_option(CodeCompletionKind p_type, const String &p_display_text, const String &p_insert_text, const Color &p_text_color, const RES &p_icon, const Variant &p_value) {
- ScriptCodeCompletionOption completion_option;
- completion_option.kind = (ScriptCodeCompletionOption::Kind)p_type;
+ ScriptLanguage::CodeCompletionOption completion_option;
+ completion_option.kind = (ScriptLanguage::CodeCompletionKind)p_type;
completion_option.display = p_display_text;
completion_option.insert_text = p_insert_text;
completion_option.font_color = p_text_color;
@@ -2261,7 +2261,7 @@ void CodeEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_automatic"), "set_auto_indent_enabled", "is_auto_indent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "indent_automatic_prefixes"), "set_auto_indent_prefixes", "get_auto_indent_prefixes");
- ADD_GROUP("Auto brace completion", "auto_brace_completion_");
+ ADD_GROUP("Auto Brace Completion", "auto_brace_completion_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_brace_completion_enabled"), "set_auto_brace_completion_enabled", "is_auto_brace_completion_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_brace_completion_highlight_matching"), "set_highlight_matching_braces_enabled", "is_highlight_matching_braces_enabled");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "auto_brace_completion_pairs"), "set_auto_brace_completion_pairs", "get_auto_brace_completion_pairs");
@@ -2702,7 +2702,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
TypedArray<Dictionary> completion_options_sources;
completion_options_sources.resize(code_completion_option_sources.size());
int i = 0;
- for (const ScriptCodeCompletionOption &E : code_completion_option_sources) {
+ for (const ScriptLanguage::CodeCompletionOption &E : code_completion_option_sources) {
Dictionary option;
option["kind"] = E.kind;
option["display_text"] = E.display;
@@ -2727,8 +2727,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
/* Convert back into options. */
int max_width = 0;
for (i = 0; i < completion_options.size(); i++) {
- ScriptCodeCompletionOption option;
- option.kind = (ScriptCodeCompletionOption::Kind)(int)completion_options[i].get("kind");
+ ScriptLanguage::CodeCompletionOption option;
+ option.kind = (ScriptLanguage::CodeCompletionKind)(int)completion_options[i].get("kind");
option.display = completion_options[i].get("display_text");
option.insert_text = completion_options[i].get("insert_text");
option.font_color = completion_options[i].get("font_color");
@@ -2821,15 +2821,15 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
code_completion_options.clear();
code_completion_base = string_to_complete;
- Vector<ScriptCodeCompletionOption> completion_options_casei;
- Vector<ScriptCodeCompletionOption> completion_options_substr;
- Vector<ScriptCodeCompletionOption> completion_options_substr_casei;
- Vector<ScriptCodeCompletionOption> completion_options_subseq;
- Vector<ScriptCodeCompletionOption> completion_options_subseq_casei;
+ Vector<ScriptLanguage::CodeCompletionOption> completion_options_casei;
+ Vector<ScriptLanguage::CodeCompletionOption> completion_options_substr;
+ Vector<ScriptLanguage::CodeCompletionOption> completion_options_substr_casei;
+ Vector<ScriptLanguage::CodeCompletionOption> completion_options_subseq;
+ Vector<ScriptLanguage::CodeCompletionOption> completion_options_subseq_casei;
int max_width = 0;
String string_to_complete_lower = string_to_complete.to_lower();
- for (ScriptCodeCompletionOption &option : code_completion_option_sources) {
+ for (ScriptLanguage::CodeCompletionOption &option : code_completion_option_sources) {
if (single_quote && option.display.is_quoted()) {
option.display = option.display.unquote().quote("'");
}
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index cb1309ced3..596a065f12 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -38,7 +38,7 @@ class CodeEdit : public TextEdit {
public:
/* Keep enum in sync with: */
- /* /core/object/script_language.h - ScriptCodeCompletionOption::Kind */
+ /* /core/object/script_language.h - ScriptLanguage::CodeCompletionKind */
enum CodeCompletionKind {
KIND_CLASS,
KIND_FUNCTION,
@@ -208,15 +208,15 @@ private:
Color code_completion_existing_color = Color(0, 0, 0, 0);
bool code_completion_active = false;
- Vector<ScriptCodeCompletionOption> code_completion_options;
+ Vector<ScriptLanguage::CodeCompletionOption> code_completion_options;
int code_completion_line_ofs = 0;
int code_completion_current_selected = 0;
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
Set<char32_t> code_completion_prefixes;
- List<ScriptCodeCompletionOption> code_completion_option_submitted;
- List<ScriptCodeCompletionOption> code_completion_option_sources;
+ List<ScriptLanguage::CodeCompletionOption> code_completion_option_submitted;
+ List<ScriptLanguage::CodeCompletionOption> code_completion_option_sources;
String code_completion_base;
void _filter_code_completion_candidates_impl();
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 9f32ac223c..48fadb0cf8 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -1221,7 +1221,7 @@ ColorPicker::ColorPicker() :
hhb->add_child(text_type);
text_type->set_text("#");
- text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
+ text_type->set_tooltip(RTR("Switch between hexadecimal and code values."));
if (Engine::get_singleton()->is_editor_hint()) {
text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
} else {
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 1dd88371ea..5512c0f1fd 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -196,7 +196,7 @@ TypedArray<String> Container::get_configuration_warnings() const {
TypedArray<String> warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) {
- warnings.push_back(TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
+ warnings.push_back(RTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
}
return warnings;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index d2d1b5e9b7..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;
@@ -2937,9 +2937,9 @@ Control::MouseFilter Control::get_mouse_filter() const {
return data.mouse_filter;
}
-void Control::warp_mouse(const Point2 &p_to_pos) {
+void Control::warp_mouse(const Point2 &p_position) {
ERR_FAIL_COND(!is_inside_tree());
- get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
+ get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position));
}
bool Control::is_text_field() const {
@@ -3141,7 +3141,7 @@ TypedArray<String> Control::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
- warnings.push_back(TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
+ warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
}
return warnings;
@@ -3331,7 +3331,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview);
ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful);
- ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Control::warp_mouse);
+ ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse);
ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index becb50a118..4240d52b65 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -44,7 +44,6 @@ class Panel;
class Control : public CanvasItem {
GDCLASS(Control, CanvasItem);
- OBJ_CATEGORY("GUI Nodes");
public:
enum Anchor {
@@ -548,7 +547,7 @@ public:
void grab_click_focus();
- void warp_mouse(const Point2 &p_to_pos);
+ void warp_mouse(const Point2 &p_position);
virtual bool is_text_field() const;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index e3744eedca..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();
}
}
@@ -93,6 +93,9 @@ void AcceptDialog::_notification(int p_what) {
}
void AcceptDialog::_text_submitted(const String &p_text) {
+ if (get_ok_button() && get_ok_button()->is_disabled()) {
+ return; // Do not allow submission if OK button is disabled.
+ }
_ok_pressed();
}
@@ -142,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);
}
@@ -285,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);
@@ -301,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.cpp b/scene/gui/file_dialog.cpp
index e71ab64535..5e74658470 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -95,7 +95,7 @@ void FileDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
- set_process_unhandled_input(false);
+ set_process_shortcut_input(false);
}
} break;
@@ -119,7 +119,7 @@ void FileDialog::_notification(int p_what) {
}
}
-void FileDialog::unhandled_input(const Ref<InputEvent> &p_event) {
+void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@@ -217,7 +217,7 @@ void FileDialog::_post_popup() {
tree->grab_focus();
}
- set_process_unhandled_input(true);
+ set_process_shortcut_input(true);
// For open dir mode, deselect all items on file dialog open.
if (mode == FILE_MODE_OPEN_DIR) {
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 7a50efe40f..b41a08c6c7 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;
@@ -133,7 +133,7 @@ private:
void _update_drives(bool p_select = true);
- virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool _is_open_should_be_disabled();
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index 3bd21f96b2..40aca555db 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -39,6 +39,11 @@ struct _LineData {
};
void FlowContainer::_resort() {
+ // Avoid resorting if invisible.
+ if (!is_visible_in_tree()) {
+ return;
+ }
+
int separation_horizontal = get_theme_constant(SNAME("hseparation"));
int separation_vertical = get_theme_constant(SNAME("vseparation"));
@@ -58,7 +63,7 @@ void FlowContainer::_resort() {
// First pass for line wrapping and minimum size calculation.
for (int i = 0; i < get_child_count(); i++) {
Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || !child->is_visible_in_tree()) {
+ if (!child || !child->is_visible()) {
continue;
}
if (child->is_set_as_top_level()) {
@@ -128,7 +133,7 @@ void FlowContainer::_resort() {
for (int i = 0; i < get_child_count(); i++) {
Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || !child->is_visible_in_tree()) {
+ if (!child || !child->is_visible()) {
continue;
}
if (child->is_set_as_top_level()) {
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/label.cpp b/scene/gui/label.cpp
index 419901d5ea..cd6fc168c2 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -115,7 +115,7 @@ void Label::_shape() {
if (lines_dirty) {
for (int i = 0; i < lines_rid.size(); i++) {
- TS->free(lines_rid[i]);
+ TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@@ -960,8 +960,8 @@ Label::Label(const String &p_text) {
Label::~Label() {
for (int i = 0; i < lines_rid.size(); i++) {
- TS->free(lines_rid[i]);
+ TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
- TS->free(text_rid);
+ TS->free_rid(text_rid);
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index da39a3d387..b3f051bb75 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -215,6 +215,27 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
}
+void LineEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ return;
+ }
+ // Handle Unicode (with modifiers active, process after shortcuts).
+ if (has_focus() && editable && (k->get_unicode() >= 32)) {
+ selection_delete();
+ char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
+ int prev_len = text.length();
+ insert_text_at_caret(ucodestr);
+ if (text.length() != prev_len) {
+ _text_changed();
+ }
+ accept_event();
+ }
+ }
+}
+
void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -2445,6 +2466,7 @@ LineEdit::LineEdit(const String &p_placeholder) {
set_focus_mode(FOCUS_ALL);
set_default_cursor_shape(CURSOR_IBEAM);
set_mouse_filter(MOUSE_FILTER_STOP);
+ set_process_unhandled_key_input(true);
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT);
@@ -2458,5 +2480,5 @@ LineEdit::LineEdit(const String &p_placeholder) {
}
LineEdit::~LineEdit() {
- TS->free(text_rid);
+ TS->free_rid(text_rid);
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 444c9a1c50..b86ccd6421 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -202,6 +202,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 7e724e4d71..1feee017c2 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -33,7 +33,7 @@
#include "core/os/keyboard.h"
#include "scene/main/window.h"
-void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
+void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shortcut_context()) {
@@ -232,7 +232,7 @@ MenuButton::MenuButton(const String &p_text) :
set_flat(true);
set_toggle_mode(true);
set_disable_shortcuts(false);
- set_process_unhandled_key_input(true);
+ set_process_shortcut_input(true);
set_focus_mode(FOCUS_NONE);
set_action_mode(ACTION_MODE_BUTTON_PRESS);
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 9cfb780255..0a6b46c796 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;
@@ -54,7 +54,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
- virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
public:
virtual void pressed() override;
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index b3804e73d9..1e8a149e11 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -240,6 +240,10 @@ void OptionButton::set_item_metadata(int p_idx, const Variant &p_metadata) {
popup->set_item_metadata(p_idx, p_metadata);
}
+void OptionButton::set_item_tooltip(int p_idx, const String &p_tooltip) {
+ popup->set_item_tooltip(p_idx, p_tooltip);
+}
+
void OptionButton::set_item_disabled(int p_idx, bool p_disabled) {
popup->set_item_disabled(p_idx, p_disabled);
}
@@ -268,6 +272,10 @@ Variant OptionButton::get_item_metadata(int p_idx) const {
return popup->get_item_metadata(p_idx);
}
+String OptionButton::get_item_tooltip(int p_idx) const {
+ return popup->get_item_tooltip(p_idx);
+}
+
bool OptionButton::is_item_disabled(int p_idx) const {
return popup->is_item_disabled(p_idx);
}
@@ -377,6 +385,12 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const {
popup->get_translatable_strings(p_strings);
}
+void OptionButton::_validate_property(PropertyInfo &property) const {
+ if (property.name == "text" || property.name == "icon") {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_item", "label", "id"), &OptionButton::add_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id"), &OptionButton::add_icon_item, DEFVAL(-1));
@@ -385,11 +399,13 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_disabled", "idx", "disabled"), &OptionButton::set_item_disabled);
ClassDB::bind_method(D_METHOD("set_item_id", "idx", "id"), &OptionButton::set_item_id);
ClassDB::bind_method(D_METHOD("set_item_metadata", "idx", "metadata"), &OptionButton::set_item_metadata);
+ ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &OptionButton::set_item_tooltip);
ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &OptionButton::get_item_text);
ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &OptionButton::get_item_icon);
ClassDB::bind_method(D_METHOD("get_item_id", "idx"), &OptionButton::get_item_id);
ClassDB::bind_method(D_METHOD("get_item_index", "id"), &OptionButton::get_item_index);
ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &OptionButton::get_item_metadata);
+ ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &OptionButton::get_item_tooltip);
ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &OptionButton::is_item_disabled);
ClassDB::bind_method(D_METHOD("add_separator"), &OptionButton::add_separator);
ClassDB::bind_method(D_METHOD("clear"), &OptionButton::clear);
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 5352fe18a6..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);
@@ -53,6 +53,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void _validate_property(PropertyInfo &property) const override;
static void _bind_methods();
public:
@@ -68,6 +69,7 @@ public:
void set_item_id(int p_idx, int p_id);
void set_item_metadata(int p_idx, const Variant &p_metadata);
void set_item_disabled(int p_idx, bool p_disabled);
+ void set_item_tooltip(int p_idx, const String &p_tooltip);
String get_item_text(int p_idx) const;
Ref<Texture2D> get_item_icon(int p_idx) const;
@@ -75,6 +77,7 @@ public:
int get_item_index(int p_id) const;
Variant get_item_metadata(int p_idx) const;
bool is_item_disabled(int p_idx) const;
+ String get_item_tooltip(int p_idx) const;
void set_item_count(int p_count);
int get_item_count() const;
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.cpp b/scene/gui/popup_menu.cpp
index 4220066b20..9fc1fb072c 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -1003,8 +1003,12 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].text == p_text) {
+ return;
+ }
items.write[p_idx].text = p_text;
items.write[p_idx].xl_text = atr(p_text);
+ items.write[p_idx].dirty = true;
_shape_item(p_idx);
control->update();
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/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 20b3513375..50ffb3ca67 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -100,7 +100,7 @@ bool ProgressBar::is_percent_visible() const {
void ProgressBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_percent_visible", "visible"), &ProgressBar::set_percent_visible);
ClassDB::bind_method(D_METHOD("is_percent_visible"), &ProgressBar::is_percent_visible);
- ADD_GROUP("Percent", "percent_");
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "percent_visible"), "set_percent_visible", "is_percent_visible");
}
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 2fb6452a97..8e66826e9d 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -34,7 +34,7 @@ TypedArray<String> Range::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
- warnings.push_back(TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
+ warnings.push_back(RTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
}
return warnings;
@@ -282,7 +282,7 @@ void Range::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed");
- GDVIRTUAL_BIND(_value_changed);
+ GDVIRTUAL_BIND(_value_changed, "new_value");
ADD_LINKED_PROPERTY("min_value", "value");
ADD_LINKED_PROPERTY("min_value", "max_value");
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 0a36176c98..981766e5eb 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -142,7 +142,7 @@ RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item
for (Item *it = p_item_from; it && it != p_item_to; it = _get_next_item(it)) {
switch (it->type) {
case ITEM_TEXT: {
- ItemText *t = (ItemText *)it;
+ ItemText *t = static_cast<ItemText *>(it);
offset += t->text.length();
if (offset > p_position) {
return it;
@@ -166,16 +166,16 @@ String RichTextLabel::_roman(int p_num, bool p_capitalize) const {
};
String s;
if (p_capitalize) {
- String M[] = { "", "M", "MM", "MMM" };
- String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
- String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
- String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
+ const String M[] = { "", "M", "MM", "MMM" };
+ const String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
+ const String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
+ const String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
} else {
- String M[] = { "", "m", "mm", "mmm" };
- String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
- String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
- String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
+ const String M[] = { "", "m", "mm", "mmm" };
+ const String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
+ const String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
+ const String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
}
return s;
@@ -215,7 +215,7 @@ void RichTextLabel::_update_line_font(ItemFrame *p_frame, int p_line, const Ref<
RID t = l.text_buf->get_rid();
int spans = TS->shaped_get_span_count(t);
for (int i = 0; i < spans; i++) {
- ItemText *it = (ItemText *)(uint64_t)TS->shaped_get_span_meta(t, i);
+ ItemText *it = reinterpret_cast<ItemText *>((uint64_t)TS->shaped_get_span_meta(t, i));
if (it) {
Ref<Font> font = _find_font(it);
if (font.is_null()) {
@@ -466,15 +466,11 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
switch (it->type) {
case ITEM_DROPCAP: {
// Add dropcap.
- const ItemDropcap *dc = (ItemDropcap *)it;
- if (dc != nullptr) {
- l.text_buf->set_dropcap(dc->text, dc->font, dc->font_size, dc->dropcap_margins);
- l.dc_color = dc->color;
- l.dc_ol_size = dc->ol_size;
- l.dc_ol_color = dc->ol_color;
- } else {
- l.text_buf->clear_dropcap();
- }
+ const ItemDropcap *dc = static_cast<ItemDropcap *>(it);
+ l.text_buf->set_dropcap(dc->text, dc->font, dc->font_size, dc->dropcap_margins);
+ l.dc_color = dc->color;
+ l.dc_ol_size = dc->ol_size;
+ l.dc_ol_color = dc->ol_color;
} break;
case ITEM_NEWLINE: {
Ref<Font> font = _find_font(it);
@@ -491,7 +487,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
remaining_characters--;
} break;
case ITEM_TEXT: {
- ItemText *t = (ItemText *)it;
+ ItemText *t = static_cast<ItemText *>(it);
Ref<Font> font = _find_font(it);
if (font.is_null()) {
font = p_base_font;
@@ -513,7 +509,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
l.char_count += tx.length();
} break;
case ITEM_IMAGE: {
- ItemImage *img = (ItemImage *)it;
+ ItemImage *img = static_cast<ItemImage *>(it);
l.text_buf->add_object((uint64_t)it, img->size, img->inline_align, 1);
text += String::chr(0xfffc);
l.char_count++;
@@ -699,7 +695,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Item *it_from = l.from;
Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
- Variant meta;
if (it_from == nullptr) {
return 0;
@@ -843,7 +838,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
// Draw inlined objects.
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
- Item *it = (Item *)(uint64_t)objects[i];
+ Item *it = reinterpret_cast<Item *>((uint64_t)objects[i]);
if (it != nullptr) {
Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
//draw_rect(rect, Color(1,0,0), false, 2); //DEBUG_RECTS
@@ -945,8 +940,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
//Apply fx.
- float faded_visibility = 1.0f;
if (fade) {
+ float faded_visibility = 1.0f;
if (glyphs[i].start >= fade->starting_index) {
faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
@@ -1070,23 +1065,60 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
+ Vector2 ul_start;
+ bool ul_started = false;
+ Color ul_color;
+
+ Vector2 dot_ul_start;
+ bool dot_ul_started = false;
+ Color dot_ul_color;
+
+ Vector2 st_start;
+ bool st_started = false;
+ Color st_color;
+
for (int i = 0; i < gl_size; i++) {
bool selected = selection.active && (sel_start != -1) && (glyphs[i].start >= sel_start) && (glyphs[i].end <= sel_end);
Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
Color font_color = _find_color(it, p_base_color);
- if (_find_underline(it) || (_find_meta(it, &meta) && underline_meta)) {
- Color uc = font_color;
- uc.a *= 0.5;
+ if (_find_underline(it) || (_find_meta(it, nullptr) && underline_meta)) {
+ if (!ul_started) {
+ ul_started = true;
+ ul_start = p_ofs + Vector2(off.x, off.y);
+ ul_color = font_color;
+ ul_color.a *= 0.5;
+ }
+ } else if (ul_started) {
+ ul_started = false;
+ float y_off = TS->shaped_text_get_underline_position(rid);
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
+ }
+ if (_find_hint(it, nullptr) && underline_hint) {
+ if (!dot_ul_started) {
+ dot_ul_started = true;
+ dot_ul_start = p_ofs + Vector2(off.x, off.y);
+ dot_ul_color = font_color;
+ dot_ul_color.a *= 0.5;
+ }
+ } else if (dot_ul_started) {
+ dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
- draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2);
}
if (_find_strikethrough(it)) {
- Color uc = font_color;
- uc.a *= 0.5;
+ if (!st_started) {
+ st_started = true;
+ st_start = p_ofs + Vector2(off.x, off.y);
+ st_color = font_color;
+ st_color.a *= 0.5;
+ }
+ } else if (st_started) {
+ st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
- draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
// Get FX.
@@ -1124,8 +1156,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
//Apply fx.
- float faded_visibility = 1.0f;
if (fade) {
+ float faded_visibility = 1.0f;
if (glyphs[i].start >= fade->starting_index) {
faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
@@ -1222,6 +1254,24 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
off.x += glyphs[i].advance;
}
}
+ if (ul_started) {
+ ul_started = false;
+ float y_off = TS->shaped_text_get_underline_position(rid);
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
+ }
+ if (dot_ul_started) {
+ dot_ul_started = false;
+ float y_off = TS->shaped_text_get_underline_position(rid);
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2);
+ }
+ if (st_started) {
+ st_started = false;
+ float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
+ }
// Draw foreground color box
_draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 1);
@@ -1276,14 +1326,22 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
}
}
-float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char) {
+float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table) {
Vector2 off;
int char_pos = -1;
Line &l = p_frame->lines.write[p_line];
bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
bool lrtl = is_layout_rtl();
+
+ // Table hit test results.
bool table_hit = false;
+ Vector2i table_range;
+ float table_offy = 0.f;
+ ItemFrame *table_click_frame = nullptr;
+ int table_click_line = -1;
+ Item *table_click_item = nullptr;
+ int table_click_char = -1;
for (int line = 0; line < l.text_buf->get_line_count(); line++) {
RID rid = l.text_buf->get_line_rid(line);
@@ -1324,10 +1382,11 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
- Item *it = (Item *)(uint64_t)objects[i];
+ Item *it = reinterpret_cast<Item *>((uint64_t)objects[i]);
if (it != nullptr) {
Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
- if (rect.has_point(p_click - p_ofs - off)) {
+ rect.position += p_ofs + off;
+ if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) {
switch (it->type) {
case ITEM_TABLE: {
int hseparation = get_theme_constant(SNAME("table_hseparation"));
@@ -1335,8 +1394,6 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
ItemTable *table = static_cast<ItemTable *>(it);
- table_hit = true;
-
int idx = 0;
int col_count = table->columns.size();
int row_count = table->rows.size();
@@ -1352,7 +1409,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (rtl) {
coff.x = rect.size.width - table->columns[col].width - coff.x;
}
- Rect2 crect = Rect2(p_ofs + off + rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size);
+ Rect2 crect = Rect2(rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size);
if (col == col_count - 1) {
if (rtl) {
crect.size.x = crect.position.x + crect.size.x;
@@ -1363,9 +1420,19 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
}
if (crect.has_point(p_click)) {
for (int j = 0; j < frame->lines.size(); j++) {
- _find_click_in_line(frame, j, p_ofs + off + rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
- if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
- return off.y;
+ _find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true);
+ if (table_click_frame && table_click_item) {
+ // Save cell detected cell hit data.
+ table_range = Vector2i(INT32_MAX, 0);
+ for (Item *F : table->subitems) {
+ ItemFrame *sub_frame = static_cast<ItemFrame *>(F);
+ for (int k = 0; k < sub_frame->lines.size(); k++) {
+ table_range.x = MIN(table_range.x, sub_frame->lines[k].char_offset);
+ table_range.y = MAX(table_range.y, sub_frame->lines[k].char_offset + sub_frame->lines[k].char_count);
+ }
+ }
+ table_offy = off.y;
+ table_hit = true;
}
}
}
@@ -1379,14 +1446,39 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
}
}
}
- Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)), Size2(get_size().x, TS->shaped_text_get_size(rid).y));
+ Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)) - p_frame->padding.position, TS->shaped_text_get_size(rid) + p_frame->padding.position + p_frame->padding.size);
+ if (p_table) {
+ rect.size.y += get_theme_constant(SNAME("table_vseparation"));
+ }
- if (rect.has_point(p_click) && !table_hit) {
+ if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) {
char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
}
+
+ // If table hit was detected, and line hit is in the table bounds use table hit.
+ if (table_hit && (((char_pos + p_frame->lines[p_line].char_offset) >= table_range.x && (char_pos + p_frame->lines[p_line].char_offset) <= table_range.y) || char_pos == -1)) {
+ if (r_click_frame != nullptr) {
+ *r_click_frame = table_click_frame;
+ }
+
+ if (r_click_line != nullptr) {
+ *r_click_line = table_click_line;
+ }
+
+ if (r_click_item != nullptr) {
+ *r_click_item = table_click_item;
+ }
+
+ if (r_click_char != nullptr) {
+ *r_click_char = table_click_char;
+ }
+ return table_offy;
+ }
+
off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom() + get_theme_constant(SNAME("line_separation"));
}
+ // Text line hit.
if (char_pos >= 0) {
// Find item.
if (r_click_item != nullptr) {
@@ -1397,7 +1489,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (it_to != nullptr) {
*r_click_item = _get_prev_item(it_to);
} else {
- for (Item *i = it; i && i != it_to; i = _get_next_item(i)) {
+ for (Item *i = it; i; i = _get_next_item(i)) {
*r_click_item = i;
}
}
@@ -1596,8 +1688,7 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_FOCUS_EXIT: {
if (deselect_on_focus_loss_enabled) {
- selection.active = false;
- update();
+ deselect();
}
} break;
@@ -1630,9 +1721,9 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
Item *item = nullptr;
bool outside = true;
- ((RichTextLabel *)(this))->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside);
+ const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside);
- if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, nullptr)) {
+ if (item && !outside && const_cast<RichTextLabel *>(this)->_find_meta(item, nullptr)) {
return CURSOR_POINTING_HAND;
}
@@ -1688,9 +1779,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();
}
}
}
@@ -1748,9 +1837,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();
}
}
@@ -1865,14 +1952,13 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
selection.to_char = c_index;
bool swap = false;
- if (selection.from_item->index > selection.to_item->index) {
- swap = true;
- } else if (selection.from_item->index == selection.to_item->index) {
- if (selection.from_char > selection.to_char) {
+ if (selection.click_frame && c_frame) {
+ const Line &l1 = c_frame->lines[c_line];
+ const Line &l2 = selection.click_frame->lines[selection.click_line];
+ if (l1.char_offset + c_index < l2.char_offset + selection.click_char) {
swap = true;
- } else if (selection.from_char == selection.to_char) {
- selection.active = false;
- update();
+ } else if (l1.char_offset + c_index == l2.char_offset + selection.click_char) {
+ deselect();
return;
}
}
@@ -1907,6 +1993,20 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
}
+String RichTextLabel::get_tooltip(const Point2 &p_pos) const {
+ Item *c_item = nullptr;
+ bool outside;
+
+ const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &c_item, nullptr, &outside);
+
+ String description;
+ if (c_item && !outside && const_cast<RichTextLabel *>(this)->_find_hint(c_item, &description)) {
+ return description;
+ } else {
+ return Control::get_tooltip(p_pos);
+ }
+}
+
void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line) {
if (r_frame != nullptr) {
*r_frame = nullptr;
@@ -1920,7 +2020,7 @@ void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line)
while (item) {
if (item->parent != nullptr && item->parent->type == ITEM_FRAME) {
if (r_frame != nullptr) {
- *r_frame = (ItemFrame *)item->parent;
+ *r_frame = static_cast<ItemFrame *>(item->parent);
}
if (r_line != nullptr) {
*r_line = item->line;
@@ -2244,6 +2344,24 @@ bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item)
return false;
}
+bool RichTextLabel::_find_hint(Item *p_item, String *r_description) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_HINT) {
+ ItemHint *hint = static_cast<ItemHint *>(item);
+ if (r_description) {
+ *r_description = hint->description;
+ }
+ return true;
+ }
+
+ item = item->parent;
+ }
+
+ return false;
+}
+
Color RichTextLabel::_find_bgcolor(Item *p_item) {
Item *item = p_item;
@@ -2437,7 +2555,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
p_item->index = current_idx++;
p_item->char_ofs = current_char_ofs;
if (p_item->type == ITEM_TEXT) {
- ItemText *t = (ItemText *)p_item;
+ ItemText *t = static_cast<ItemText *>(p_item);
current_char_ofs += t->text.length();
} else if (p_item->type == ITEM_IMAGE) {
current_char_ofs++;
@@ -2736,6 +2854,14 @@ void RichTextLabel::push_meta(const Variant &p_meta) {
_add_item(item, true);
}
+void RichTextLabel::push_hint(const String &p_string) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemHint *item = memnew(ItemHint);
+
+ item->description = p_string;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_table(int p_columns, InlineAlignment p_alignment) {
ERR_FAIL_COND(p_columns < 1);
ItemTable *item = memnew(ItemTable);
@@ -2883,11 +3009,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;
@@ -2930,6 +3055,15 @@ bool RichTextLabel::is_meta_underlined() const {
return underline_meta;
}
+void RichTextLabel::set_hint_underline(bool p_underline) {
+ underline_hint = p_underline;
+ update();
+}
+
+bool RichTextLabel::is_hint_underlined() const {
+ return underline_hint;
+}
+
void RichTextLabel::set_override_selected_font_color(bool p_override_selected_font_color) {
override_selected_font_color = p_override_selected_font_color;
}
@@ -3367,6 +3501,11 @@ void RichTextLabel::append_text(const String &p_bbcode) {
push_meta(url);
pos = brk_end + 1;
tag_stack.push_front("url");
+ } else if (tag.begins_with("hint=")) {
+ String description = tag.substr(5, tag.length());
+ push_hint(description);
+ pos = brk_end + 1;
+ tag_stack.push_front("hint");
} else if (tag.begins_with("dropcap")) {
Vector<String> subtag = tag.substr(5, tag.length()).split(" ");
Ref<Font> f = get_theme_font(SNAME("normal_font"));
@@ -3782,8 +3921,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 {
@@ -3794,8 +3932,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();
}
}
@@ -3859,7 +3996,7 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
text += "\n";
} break;
case ITEM_TEXT: {
- ItemText *t = (ItemText *)it;
+ ItemText *t = static_cast<ItemText *>(it);
text += t->text;
} break;
case ITEM_IMAGE: {
@@ -3992,7 +4129,7 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
if (it_to != nullptr) {
end_idx = it_to->index;
} else {
- for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ for (Item *it = l.from; it; it = _get_next_item(it)) {
end_idx = it->index + 1;
}
}
@@ -4046,6 +4183,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();
@@ -4110,10 +4252,8 @@ String RichTextLabel::get_parsed_text() const {
Item *it = main;
while (it) {
if (it->type == ITEM_DROPCAP) {
- const ItemDropcap *dc = (ItemDropcap *)it;
- if (dc != nullptr) {
- text += dc->text;
- }
+ ItemDropcap *dc = static_cast<ItemDropcap *>(it);
+ text += dc->text;
} else if (it->type == ITEM_TEXT) {
ItemText *t = static_cast<ItemText *>(it);
text += t->text;
@@ -4287,6 +4427,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent);
ClassDB::bind_method(D_METHOD("push_list", "level", "type", "capitalize"), &RichTextLabel::push_list);
ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta);
+ ClassDB::bind_method(D_METHOD("push_hint", "description"), &RichTextLabel::push_hint);
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGNMENT_TOP));
@@ -4318,6 +4459,9 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta_underline", "enable"), &RichTextLabel::set_meta_underline);
ClassDB::bind_method(D_METHOD("is_meta_underlined"), &RichTextLabel::is_meta_underlined);
+ ClassDB::bind_method(D_METHOD("set_hint_underline", "enable"), &RichTextLabel::set_hint_underline);
+ ClassDB::bind_method(D_METHOD("is_hint_underlined"), &RichTextLabel::is_hint_underlined);
+
ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &RichTextLabel::set_override_selected_font_color);
ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &RichTextLabel::is_overriding_selected_font_color);
@@ -4348,6 +4492,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);
@@ -4388,7 +4533,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_effects"), &RichTextLabel::get_effects);
ClassDB::bind_method(D_METHOD("install_effect", "effect"), &RichTextLabel::install_effect);
- // Note: set "bbcode_enabled" first, to avoid unnecessery "text" resets.
+ // Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
@@ -4401,6 +4546,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hint_underlined"), "set_hint_underline", "is_hint_underlined");
ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
// Note: "visible_characters" and "percent_visible" should be set after "text" to be correctly applied.
@@ -4454,6 +4600,7 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_BGCOLOR);
BIND_ENUM_CONSTANT(ITEM_FGCOLOR);
BIND_ENUM_CONSTANT(ITEM_META);
+ BIND_ENUM_CONSTANT(ITEM_HINT);
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
@@ -4593,7 +4740,7 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
// Draw a box based on color tags associated with glyphs
for (int i = start; i < end; i++) {
Item *it = _get_item_at_pos(it_from, it_to, i);
- Color color = Color(0, 0, 0, 0);
+ Color color;
if (fbg_flag == 0) {
color = _find_bgcolor(it);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 076b68a0da..b710413987 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -78,6 +78,7 @@ public:
ITEM_BGCOLOR,
ITEM_FGCOLOR,
ITEM_META,
+ ITEM_HINT,
ITEM_DROPCAP,
ITEM_CUSTOMFX
};
@@ -218,6 +219,11 @@ private:
ItemMeta() { type = ITEM_META; }
};
+ struct ItemHint : public Item {
+ String description;
+ ItemHint() { type = ITEM_HINT; }
+ };
+
struct ItemParagraph : public Item {
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
String language;
@@ -369,6 +375,7 @@ private:
int tab_size = 4;
bool underline_meta = true;
+ bool underline_hint = true;
bool override_selected_font_color = false;
HorizontalAlignment default_alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -428,7 +435,7 @@ private:
void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size);
int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
- float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr);
+ float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false);
String _roman(int p_num, bool p_capitalize) const;
String _letters(int p_num, bool p_capitalize) const;
@@ -452,6 +459,7 @@ private:
bool _find_underline(Item *p_item);
bool _find_strikethrough(Item *p_item);
bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr);
+ bool _find_hint(Item *p_item, String *r_description);
Color _find_bgcolor(Item *p_item);
Color _find_fgcolor(Item *p_item);
bool _find_layout_subitem(Item *from, Item *to);
@@ -462,6 +470,7 @@ private:
void _scroll_changed(double);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual String get_tooltip(const Point2 &p_pos) const override;
Item *_get_next_item(Item *p_item, bool p_free = false) const;
Item *_get_prev_item(Item *p_item, bool p_free = false) const;
@@ -505,6 +514,7 @@ public:
void push_indent(int p_level);
void push_list(int p_level, ListType p_list, bool p_capitalize);
void push_meta(const Variant &p_meta);
+ void push_hint(const String &p_string);
void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP);
void push_fade(int p_start_index, int p_length);
void push_shake(int p_strength, float p_rate);
@@ -530,6 +540,9 @@ public:
void set_meta_underline(bool p_underline);
bool is_meta_underlined() const;
+ void set_hint_underline(bool p_underline);
+ bool is_hint_underlined() const;
+
void set_override_selected_font_color(bool p_override_selected_font_color);
bool is_overriding_selected_font_color() const;
@@ -574,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.cpp b/scene/gui/scroll_container.cpp
index b3cf2cbf7e..135bad4689 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -533,7 +533,7 @@ TypedArray<String> ScrollContainer::get_configuration_warnings() const {
}
if (found != 1) {
- warnings.push_back(TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."));
+ warnings.push_back(RTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."));
}
return warnings;
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/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index c66e145bc4..68281b6a72 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -176,7 +176,7 @@ void SubViewportContainer::input(const Ref<InputEvent> &p_event) {
return;
}
- Transform2D xform = get_global_transform();
+ Transform2D xform = get_global_transform_with_canvas();
if (stretch) {
Transform2D scale_xf;
@@ -203,7 +203,7 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
return;
}
- Transform2D xform = get_global_transform();
+ Transform2D xform = get_global_transform_with_canvas();
if (stretch) {
Transform2D scale_xf;
@@ -223,6 +223,23 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
}
}
+TypedArray<String> SubViewportContainer::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ bool has_viewport = false;
+ for (int i = 0; i < get_child_count(); i++) {
+ if (Object::cast_to<SubViewport>(get_child(i))) {
+ has_viewport = true;
+ break;
+ }
+ }
+ if (!has_viewport) {
+ warnings.push_back(RTR("This node doesn't have a SubViewport as child, so it can't display its intended content.\nConsider adding a SubViewport as a child to provide something displayable."));
+ }
+
+ return warnings;
+}
+
void SubViewportContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &SubViewportContainer::set_stretch);
ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &SubViewportContainer::is_stretch_enabled);
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index f52f01e4e2..55b7802aa4 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -58,6 +58,8 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
virtual Vector<int> get_allowed_size_flags_vertical() const override;
+ TypedArray<String> get_configuration_warnings() const override;
+
SubViewportContainer();
};
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index af314b9545..ce2dca0ea3 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -35,6 +35,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
+#include "scene/main/viewport.h"
Size2 TabBar::get_minimum_size() const {
Size2 ms;
@@ -158,7 +159,13 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
+ if (get_viewport()->gui_is_dragging() && can_drop_data(pos, get_viewport()->gui_get_drag_data())) {
+ dragging_valid_tab = true;
+ update();
+ }
+
_update_hover();
+
return;
}
@@ -333,6 +340,13 @@ void TabBar::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_DRAG_END: {
+ if (dragging_valid_tab) {
+ dragging_valid_tab = false;
+ update();
+ }
+ } break;
+
case NOTIFICATION_DRAW: {
if (tabs.is_empty()) {
return;
@@ -346,8 +360,6 @@ void TabBar::_notification(int p_what) {
Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
- Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
bool rtl = is_layout_rtl();
Vector2 size = get_size();
@@ -391,7 +403,10 @@ void TabBar::_notification(int p_what) {
}
if (buttons_visible) {
- int vofs = (get_size().height - incr->get_size().height) / 2;
+ Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
+ Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
+
+ int vofs = (size.height - incr->get_size().height) / 2;
if (rtl) {
if (missing_right) {
@@ -419,6 +434,39 @@ void TabBar::_notification(int p_what) {
}
}
}
+
+ if (dragging_valid_tab) {
+ int x;
+
+ int tab_hover = get_hovered_tab();
+ if (tab_hover != -1) {
+ Rect2 tab_rect = get_tab_rect(tab_hover);
+
+ x = tab_rect.position.x;
+ if (get_local_mouse_position().x > x + tab_rect.size.width / 2) {
+ x += tab_rect.size.width;
+ }
+ } else {
+ if (rtl ^ (get_local_mouse_position().x < get_tab_rect(0).position.x)) {
+ x = get_tab_rect(0).position.x;
+ if (rtl) {
+ x += get_tab_rect(0).size.width;
+ }
+ } else {
+ Rect2 tab_rect = get_tab_rect(get_tab_count() - 1);
+
+ x = tab_rect.position.x;
+ if (!rtl) {
+ x += tab_rect.size.width;
+ }
+ }
+ }
+
+ Ref<Texture2D> drop_mark = get_theme_icon(SNAME("drop_mark"));
+ Color drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
+
+ drop_mark->draw(get_canvas_item(), Point2(x - drop_mark->get_width() / 2, (size.height - drop_mark->get_height()) / 2), drop_mark_color);
+ }
} break;
}
}
@@ -906,6 +954,8 @@ void TabBar::_on_mouse_exited() {
cb_hover = -1;
hover = -1;
highlight_arrow = -1;
+ dragging_valid_tab = false;
+
update();
}
@@ -1057,13 +1107,29 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
NodePath to_path = get_path();
if (from_path == to_path) {
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
+ if (tab_from_id == hover_now) {
+ return;
+ }
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x <= tab_rect.position.x + tab_rect.size.width / 2)) {
+ if (hover_now > tab_from_id) {
+ hover_now -= 1;
+ }
+ } else if (tab_from_id > hover_now) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1;
}
move_tab(tab_from_id, hover_now);
- emit_signal(SNAME("active_tab_rearranged"), hover_now);
- set_current_tab(hover_now);
+ if (!is_tab_disabled(hover_now)) {
+ emit_signal(SNAME("active_tab_rearranged"), hover_now);
+ set_current_tab(hover_now);
+ }
} else if (get_tabs_rearrange_group() != -1) {
// Drag and drop between Tabs.
@@ -1075,11 +1141,17 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
return;
}
- Tab moving_tab = from_tabs->tabs[tab_from_id];
- if (hover_now < 0) {
- hover_now = get_tab_count();
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x > tab_rect.position.x + tab_rect.size.width / 2)) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count();
}
+ Tab moving_tab = from_tabs->tabs[tab_from_id];
from_tabs->remove_tab(tab_from_id);
tabs.insert(hover_now, moving_tab);
@@ -1092,7 +1164,13 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
}
}
- set_current_tab(hover_now);
+ if (!is_tab_disabled(hover_now)) {
+ set_current_tab(hover_now);
+ } else {
+ _update_cache();
+ update();
+ }
+
update_minimum_size();
if (tabs.size() == 1) {
@@ -1530,7 +1608,7 @@ void TabBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_tab_width", PROPERTY_HINT_RANGE, "0,99999,1"), "set_max_tab_width", "get_max_tab_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_to_selected"), "set_scroll_to_selected", "get_scroll_to_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_with_rmb"), "set_select_with_rmb", "get_select_with_rmb");
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index 0f2184aca7..548a2e62af 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -86,7 +86,7 @@ private:
Vector<Tab> tabs;
int current = 0;
int previous = 0;
- AlignmentMode tab_alignment = ALIGNMENT_CENTER;
+ AlignmentMode tab_alignment = ALIGNMENT_LEFT;
bool clip_tabs = true;
int rb_hover = -1;
bool rb_pressing = false;
@@ -101,6 +101,7 @@ private:
int max_width = 0;
bool scrolling_enabled = true;
bool drag_to_rearrange_enabled = false;
+ bool dragging_valid_tab = false;
bool scroll_to_selected = true;
int tabs_rearrange_group = -1;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index ee61c862b7..84a62c71c2 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -173,9 +173,9 @@ void TabContainer::_notification(int p_what) {
int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
if (menu_hovered) {
- menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2));
+ menu_hl->draw(get_canvas_item(), Point2(x, (header_height - menu_hl->get_height()) / 2));
} else {
- menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2));
+ menu->draw(get_canvas_item(), Point2(x, (header_height - menu->get_height()) / 2));
}
}
} break;
@@ -201,13 +201,15 @@ void TabContainer::_on_theme_changed() {
tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight")));
tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement")));
tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight")));
+ tab_bar->add_theme_icon_override(SNAME("drop_mark"), get_theme_icon(SNAME("drop_mark")));
+ tab_bar->add_theme_color_override(SNAME("drop_mark_color"), get_theme_color(SNAME("drop_mark_color")));
tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color")));
tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color")));
tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color")));
tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color")));
tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font")));
tab_bar->add_theme_constant_override(SNAME("font_size"), get_theme_constant(SNAME("font_size")));
- tab_bar->add_theme_constant_override(SNAME("icon_separation"), get_theme_constant(SNAME("icon_separation")));
+ tab_bar->add_theme_constant_override(SNAME("hseparation"), get_theme_constant(SNAME("icon_separation")));
tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size")));
_update_margins();
@@ -384,8 +386,6 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
return;
}
- int hover_now = get_tab_idx_at_point(p_point);
-
Dictionary d = p_data;
if (!d.has("type")) {
return;
@@ -393,11 +393,27 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
if (String(d["type"]) == "tabc_element") {
int tab_from_id = d["tabc_element"];
+ int hover_now = get_tab_idx_at_point(p_point);
NodePath from_path = d["from_path"];
NodePath to_path = get_path();
+
if (from_path == to_path) {
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
+ if (tab_from_id == hover_now) {
+ return;
+ }
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = tab_bar->get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x <= tab_rect.position.x + tab_rect.size.width / 2)) {
+ if (hover_now > tab_from_id) {
+ hover_now -= 1;
+ }
+ } else if (tab_from_id > hover_now) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1;
}
move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false));
@@ -407,16 +423,31 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
} else if (get_tabs_rearrange_group() != -1) {
// Drag and drop between TabContainers.
+
Node *from_node = get_node(from_path);
TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
+
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
+ // Get the tab properties before they get erased by the child removal.
+ String tab_title = from_tabc->get_tab_title(tab_from_id);
+ bool tab_disabled = from_tabc->is_tab_disabled(tab_from_id);
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = tab_bar->get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x > tab_rect.position.x + tab_rect.size.width / 2)) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count();
+ }
+
Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
from_tabc->remove_child(moving_tabc);
add_child(moving_tabc, true);
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
- }
+ set_tab_title(get_tab_count() - 1, tab_title);
+ set_tab_disabled(get_tab_count() - 1, tab_disabled);
move_child(moving_tabc, get_tab_control(hover_now)->get_index(false));
if (!is_tab_disabled(hover_now)) {
@@ -441,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++) {
@@ -466,6 +501,9 @@ void TabContainer::add_child_notify(Node *p_child) {
tab_bar->add_tab(p_child->get_name());
_update_margins();
+ if (get_tab_count() == 1) {
+ update();
+ }
p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names));
@@ -514,6 +552,9 @@ void TabContainer::remove_child_notify(Node *p_child) {
tab_bar->remove_tab(get_tab_idx_from_control(c));
_update_margins();
+ if (get_tab_count() == 0) {
+ update();
+ }
if (p_child->has_meta("_tab_name")) {
p_child->remove_meta("_tab_name");
@@ -696,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++) {
@@ -840,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);
@@ -859,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");
@@ -878,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..86969e3ef4 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;
@@ -1537,6 +1542,21 @@ void TextEdit::_notification(int p_what) {
}
}
+void TextEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ return;
+ }
+ // Handle Unicode (with modifiers active, process after shortcuts).
+ if (has_focus() && editable && (k->get_unicode() >= 32)) {
+ handle_unicode_input(k->get_unicode());
+ accept_event();
+ }
+ }
+}
+
void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
ERR_FAIL_COND(p_gui_input.is_null());
@@ -2133,16 +2153,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 +2209,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 +2394,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 +2411,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;
}
@@ -3461,9 +3501,6 @@ void TextEdit::undo() {
TextOperation op = undo_stack_pos->get();
_do_text_op(op, true);
- if (op.type != TextOperation::TYPE_INSERT && (op.from_line != op.to_line || op.to_column != op.from_column + 1)) {
- select(op.from_line, op.from_column, op.to_line, op.to_column);
- }
current_op.version = op.prev_version;
if (undo_stack_pos->get().chain_backward) {
@@ -3479,6 +3516,10 @@ void TextEdit::undo() {
}
}
+ if (op.type != TextOperation::TYPE_INSERT && (op.from_line != op.to_line || op.to_column != op.from_column + 1)) {
+ select(op.from_line, op.from_column, op.to_line, op.to_column);
+ }
+
_update_scrollbars();
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
set_caret_line(undo_stack_pos->get().to_line, false);
@@ -4390,6 +4431,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;
}
@@ -6592,6 +6635,7 @@ TextEdit::TextEdit(const String &p_placeholder) {
set_focus_mode(FOCUS_ALL);
_update_caches();
set_default_cursor_shape(CURSOR_IBEAM);
+ set_process_unhandled_key_input(true);
text.set_tab_size(text.get_tab_size());
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 6deaf76e5e..b365e9c61c 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;
@@ -623,6 +623,7 @@ protected:
public:
/* General overrides. */
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
virtual Size2 get_minimum_size() const override;
virtual bool is_text_field() const override;
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 043c0f464c..f79c68671c 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -629,26 +629,30 @@ void TextureProgressBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_nine_patch_stretch", "stretch"), &TextureProgressBar::set_nine_patch_stretch);
ClassDB::bind_method(D_METHOD("get_nine_patch_stretch"), &TextureProgressBar::get_nine_patch_stretch);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "nine_patch_stretch"), "set_nine_patch_stretch", "get_nine_patch_stretch");
+
+ ADD_GROUP("Stretch Margin", "stretch_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_BOTTOM);
+
ADD_GROUP("Textures", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_over_texture", "get_over_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_progress_texture", "get_progress_texture");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_progress_offset"), "set_texture_progress_offset", "get_texture_progress_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
+
ADD_GROUP("Tint", "tint_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over"), "set_tint_over", "get_tint_over");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_progress"), "set_tint_progress", "get_tint_progress");
+
ADD_GROUP("Radial Fill", "radial_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_radial_initial_angle", "get_radial_initial_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_fill_degrees", "get_fill_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "radial_center_offset"), "set_radial_center_offset", "get_radial_center_offset");
- ADD_GROUP("Stretch", "stretch_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "nine_patch_stretch"), "set_nine_patch_stretch", "get_nine_patch_stretch");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_BOTTOM);
BIND_ENUM_CONSTANT(FILL_LEFT_TO_RIGHT);
BIND_ENUM_CONSTANT(FILL_RIGHT_TO_LEFT);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index ff8d2b88b1..ccd24ed2cf 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1162,24 +1162,23 @@ Size2 TreeItem::get_minimum_size(int p_column) {
return cell.cached_minimum_size;
}
-Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+void TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
- return Variant();
+ return;
}
if (p_args[0]->get_type() != Variant::STRING && p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING_NAME;
- return Variant();
+ return;
}
StringName method = *p_args[0];
call_recursive(method, &p_args[1], p_argcount - 1, r_error);
- return Variant();
}
void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index dc786de6dc..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);
@@ -189,7 +189,7 @@ protected:
return d;
}
- Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
public:
/* cell mode */
@@ -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/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index d7c76aa070..ca2dad71af 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -60,7 +60,7 @@ int VideoStreamPlayer::_audio_mix_callback(void *p_udata, const float *p_data, i
ERR_FAIL_NULL_V(p_udata, 0);
ERR_FAIL_NULL_V(p_data, 0);
- VideoStreamPlayer *vp = (VideoStreamPlayer *)p_udata;
+ VideoStreamPlayer *vp = static_cast<VideoStreamPlayer *>(p_udata);
int todo = MIN(vp->resampler.get_writer_space(), p_frames);
@@ -77,7 +77,7 @@ int VideoStreamPlayer::_audio_mix_callback(void *p_udata, const float *p_data, i
void VideoStreamPlayer::_mix_audios(void *p_self) {
ERR_FAIL_NULL(p_self);
- reinterpret_cast<VideoStreamPlayer *>(p_self)->_mix_audio();
+ static_cast<VideoStreamPlayer *>(p_self)->_mix_audio();
}
// Called from audio thread
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()) {