summaryrefslogtreecommitdiff
path: root/scene/gui/control.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/control.cpp')
-rw-r--r--scene/gui/control.cpp970
1 files changed, 409 insertions, 561 deletions
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 06aa913eb1..c5cb7157e8 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -43,6 +43,8 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
+#include "scene/theme/theme_owner.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -193,15 +195,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
List<StringName> sn;
String pf = p_function;
if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
- Theme::get_default()->get_color_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(get_class(), &sn);
} else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
- Theme::get_default()->get_stylebox_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(get_class(), &sn);
} else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
- Theme::get_default()->get_font_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(get_class(), &sn);
} else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
- Theme::get_default()->get_font_size_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(get_class(), &sn);
} else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
- Theme::get_default()->get_constant_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(get_class(), &sn);
}
sn.sort_custom<StringName::AlphCompare>();
@@ -211,8 +213,8 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
}
}
-TypedArray<String> Control::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Control::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
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\"."));
@@ -252,36 +254,36 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (data.icon_override.has(dname)) {
- data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.style_override.has(dname)) {
- data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (data.font_override.has(dname)) {
- data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_font_sizes/")) {
String dname = name.get_slicec('/', 1);
data.font_size_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_colors/")) {
String dname = name.get_slicec('/', 1);
data.color_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_constants/")) {
String dname = name.get_slicec('/', 1);
data.constant_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else {
return false;
}
@@ -344,7 +346,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();
+ Ref<Theme> theme = ThemeDB::get_singleton()->get_default_theme();
p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
@@ -422,16 +424,16 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Control::_validate_property(PropertyInfo &property) const {
+void Control::_validate_property(PropertyInfo &p_property) const {
// Update theme type variation options.
- if (property.name == "theme_type_variation") {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
@@ -447,18 +449,18 @@ void Control::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
- if (property.name == "mouse_force_pass_scroll_events") {
+ if (p_property.name == "mouse_force_pass_scroll_events") {
// Disable force pass if the control is not stopping the event.
if (data.mouse_filter != MOUSE_FILTER_STOP) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
- if (property.name == "scale") {
- property.hint = PROPERTY_HINT_LINK;
+ if (p_property.name == "scale") {
+ p_property.hint = PROPERTY_HINT_LINK;
}
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
@@ -467,33 +469,33 @@ void Control::_validate_property(PropertyInfo &property) const {
// If there is no parent, display both anchor and container options.
// Set the layout mode to be disabled with the proper value.
- if (property.name == "layout_mode") {
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "layout_mode") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_custom_anchors = _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
} else if (Object::cast_to<Container>(parent_node)) {
// If the parent is a container, display only container-related properties.
- if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" ||
- property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_") || p_property.name == "anchors_preset" ||
+ p_property.name == "position" || p_property.name == "rotation" || p_property.name == "scale" || p_property.name == "size" || p_property.name == "pivot_offset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be disabled with the proper value.
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "size_flags_horizontal" || property.name == "size_flags_vertical") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "size_flags_horizontal" || p_property.name == "size_flags_vertical") {
// Filter allowed size flags based on the parent container configuration.
Container *parent_container = Object::cast_to<Container>(parent_node);
Vector<int> size_flags;
- if (property.name == "size_flags_horizontal") {
+ if (p_property.name == "size_flags_horizontal") {
size_flags = parent_container->get_allowed_size_flags_horizontal();
- } else if (property.name == "size_flags_vertical") {
+ } else if (p_property.name == "size_flags_vertical") {
size_flags = parent_container->get_allowed_size_flags_vertical();
}
@@ -522,30 +524,30 @@ void Control::_validate_property(PropertyInfo &property) const {
}
if (hint_string.is_empty()) {
- property.hint_string = "";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.hint_string = "";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
} else {
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
} else {
// If the parent is NOT a container or not a control at all, display only anchoring-related properties.
- if (property.name.begins_with("size_flags_")) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("size_flags_")) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be enabled with proper options.
- property.hint_string = "Position,Anchors";
+ p_property.hint_string = "Position,Anchors";
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_anchors = _get_layout_mode() == LayoutMode::LAYOUT_MODE_ANCHORS;
- if (!use_anchors && property.name == "anchors_preset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_anchors && p_property.name == "anchors_preset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
bool use_custom_anchors = use_anchors && _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
}
@@ -555,16 +557,36 @@ void Control::_validate_property(PropertyInfo &property) const {
}
bool property_is_managed_by_container = false;
for (unsigned i = 0; i < properties_managed_by_container_count; i++) {
- property_is_managed_by_container = properties_managed_by_container[i] == property.name;
+ property_is_managed_by_container = properties_managed_by_container[i] == p_property.name;
if (property_is_managed_by_container) {
break;
}
}
if (property_is_managed_by_container) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
+bool Control::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "layout_mode" || p_name == "anchors_preset") {
+ return true;
+ }
+
+ return false;
+}
+
+bool Control::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "layout_mode") {
+ r_property = _get_default_layout_mode();
+ return true;
+ } else if (p_name == "anchors_preset") {
+ r_property = LayoutPreset::PRESET_TOP_LEFT;
+ return true;
+ }
+
+ return false;
+}
+
// Global relations.
bool Control::is_top_level_control() const {
@@ -611,7 +633,7 @@ Rect2 Control::get_parent_anchorable_rect() const {
#ifdef TOOLS_ENABLED
Node *edited_root = get_tree()->get_edited_scene_root();
if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) {
- parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ parent_rect.size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
} else {
parent_rect = get_viewport()->get_visible_rect();
}
@@ -692,7 +714,7 @@ void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool
_size_changed();
}
- update();
+ queue_redraw();
}
real_t Control::get_anchor(Side p_side) const {
@@ -703,6 +725,9 @@ real_t Control::get_anchor(Side p_side) const {
void Control::set_offset(Side p_side, real_t p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
+ if (data.offset[p_side] == p_value) {
+ return;
+ }
data.offset[p_side] = p_value;
_size_changed();
@@ -720,6 +745,10 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
}
void Control::set_begin(const Size2 &p_point) {
+ if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
+ return;
+ }
+
data.offset[0] = p_point.x;
data.offset[1] = p_point.y;
_size_changed();
@@ -730,6 +759,10 @@ Size2 Control::get_begin() const {
}
void Control::set_end(const Size2 &p_point) {
+ if (data.offset[2] == p_point.x && data.offset[3] == p_point.y) {
+ return;
+ }
+
data.offset[2] = p_point.x;
data.offset[3] = p_point.y;
_size_changed();
@@ -740,6 +773,10 @@ Size2 Control::get_end() const {
}
void Control::set_h_grow_direction(GrowDirection p_direction) {
+ if (data.h_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.h_grow = p_direction;
@@ -751,6 +788,10 @@ Control::GrowDirection Control::get_h_grow_direction() const {
}
void Control::set_v_grow_direction(GrowDirection p_direction) {
+ if (data.v_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.v_grow = p_direction;
@@ -794,24 +835,15 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (
void Control::_set_layout_mode(LayoutMode p_mode) {
bool list_changed = false;
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION || p_mode == LayoutMode::LAYOUT_MODE_ANCHORS) {
- if ((int)get_meta("_edit_layout_mode", p_mode) != (int)p_mode) {
- list_changed = true;
- }
-
- set_meta("_edit_layout_mode", (int)p_mode);
+ if (data.stored_layout_mode != p_mode) {
+ list_changed = true;
+ data.stored_layout_mode = p_mode;
+ }
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION) {
- remove_meta("_edit_layout_mode");
- remove_meta("_edit_use_custom_anchors");
- set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
- set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
- }
- } else {
- if (has_meta("_edit_layout_mode")) {
- remove_meta("_edit_layout_mode");
- list_changed = true;
- }
+ if (data.stored_layout_mode == LayoutMode::LAYOUT_MODE_POSITION) {
+ data.stored_use_custom_anchors = false;
+ set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
+ set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
}
if (list_changed) {
@@ -832,33 +864,43 @@ Control::LayoutMode Control::_get_layout_mode() const {
if (_get_anchors_layout_preset() != (int)LayoutPreset::PRESET_TOP_LEFT) {
return LayoutMode::LAYOUT_MODE_ANCHORS;
}
- // Otherwise check what was saved.
- if (has_meta("_edit_layout_mode")) {
- return (LayoutMode)(int)get_meta("_edit_layout_mode");
+
+ // Otherwise fallback on what's stored.
+ return data.stored_layout_mode;
+}
+
+Control::LayoutMode Control::_get_default_layout_mode() const {
+ Node *parent_node = get_parent_control();
+ // In these modes the property is read-only.
+ if (!parent_node) {
+ return LayoutMode::LAYOUT_MODE_UNCONTROLLED;
+ } else if (Object::cast_to<Container>(parent_node)) {
+ return LayoutMode::LAYOUT_MODE_CONTAINER;
}
- // Or fallback on default.
+
+ // Otherwise fallback on the position mode.
return LayoutMode::LAYOUT_MODE_POSITION;
}
void Control::_set_anchors_layout_preset(int p_preset) {
bool list_changed = false;
- if (get_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS).operator int() != LayoutMode::LAYOUT_MODE_ANCHORS) {
+ if (data.stored_layout_mode != LayoutMode::LAYOUT_MODE_ANCHORS) {
list_changed = true;
- set_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS);
+ data.stored_layout_mode = LayoutMode::LAYOUT_MODE_ANCHORS;
}
if (p_preset == -1) {
- if (!get_meta("_edit_use_custom_anchors", false)) {
- set_meta("_edit_use_custom_anchors", true);
+ if (!data.stored_use_custom_anchors) {
+ data.stored_use_custom_anchors = true;
notify_property_list_changed();
}
return; // Keep settings as is.
}
- if (get_meta("_edit_use_custom_anchors", true)) {
+ if (data.stored_use_custom_anchors) {
list_changed = true;
- remove_meta("_edit_use_custom_anchors");
+ data.stored_use_custom_anchors = false;
}
LayoutPreset preset = (LayoutPreset)p_preset;
@@ -899,7 +941,7 @@ void Control::_set_anchors_layout_preset(int p_preset) {
int Control::_get_anchors_layout_preset() const {
// If the custom preset was selected by user, use it.
- if ((bool)get_meta("_edit_use_custom_anchors", false)) {
+ if (data.stored_use_custom_anchors) {
return -1;
}
@@ -1394,18 +1436,15 @@ Rect2 Control::get_screen_rect() const {
return r;
}
-Rect2 Control::get_window_rect() const {
- ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2 gr = get_global_rect();
- gr.position += get_viewport()->get_visible_rect().position;
- return gr;
-}
-
Rect2 Control::get_anchorable_rect() const {
return Rect2(Point2(), get_size());
}
void Control::set_scale(const Vector2 &p_scale) {
+ if (data.scale == p_scale) {
+ return;
+ }
+
data.scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if (data.scale.x == 0) {
@@ -1414,7 +1453,7 @@ void Control::set_scale(const Vector2 &p_scale) {
if (data.scale.y == 0) {
data.scale.y = CMP_EPSILON;
}
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1423,8 +1462,12 @@ Vector2 Control::get_scale() const {
}
void Control::set_rotation(real_t p_radians) {
+ if (data.rotation == p_radians) {
+ return;
+ }
+
data.rotation = p_radians;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1433,8 +1476,12 @@ real_t Control::get_rotation() const {
}
void Control::set_pivot_offset(const Vector2 &p_pivot) {
+ if (data.pivot_offset == p_pivot) {
+ return;
+ }
+
data.pivot_offset = p_pivot;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1504,10 +1551,8 @@ bool Control::is_minimum_size_adjust_blocked() const {
Size2 Control::get_minimum_size() const {
Vector2 ms;
- if (GDVIRTUAL_CALL(_get_minimum_size, ms)) {
- return ms;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_get_minimum_size, ms);
+ return ms;
}
void Control::set_custom_minimum_size(const Size2 &p_custom) {
@@ -1705,6 +1750,34 @@ void Control::warp_mouse(const Point2 &p_position) {
get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position));
}
+void Control::set_shortcut_context(const Node *p_node) {
+ if (p_node != nullptr) {
+ data.shortcut_context = p_node->get_instance_id();
+ } else {
+ data.shortcut_context = ObjectID();
+ }
+}
+
+Node *Control::get_shortcut_context() const {
+ Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context);
+ Node *ctx_node = Object::cast_to<Node>(ctx_obj);
+
+ return ctx_node;
+}
+
+bool Control::is_focus_owner_in_shortcut_context() const {
+ if (data.shortcut_context == ObjectID()) {
+ // No context, therefore global - always "in" context.
+ return true;
+ }
+
+ const Node *ctx_node = get_shortcut_context();
+ const Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
+
+ // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
+ return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+}
+
// Drag and drop handling.
void Control::set_drag_forwarding(Object *p_target) {
@@ -1724,11 +1797,8 @@ Variant Control::get_drag_data(const Point2 &p_point) {
}
Variant dd;
- if (GDVIRTUAL_CALL(_get_drag_data, p_point, dd)) {
- return dd;
- }
-
- return Variant();
+ GDVIRTUAL_CALL(_get_drag_data, p_point, dd);
+ return dd;
}
bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
@@ -1739,11 +1809,9 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
}
}
- bool ret;
- if (GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret);
+ return ret;
}
void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
@@ -2171,7 +2239,19 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
void Control::set_default_cursor_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX);
+ if (data.default_cursor == p_shape) {
+ return;
+ }
data.default_cursor = p_shape;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+ if (!get_global_rect().has_point(get_global_mouse_position())) {
+ return;
+ }
+
+ get_viewport()->get_base_window()->update_mouse_cursor_shape();
}
Control::CursorShape Control::get_default_cursor_shape() const {
@@ -2183,8 +2263,11 @@ Control::CursorShape Control::get_cursor_shape(const Point2 &p_pos) const {
}
void Control::set_disable_visibility_clip(bool p_ignore) {
+ if (data.disable_visibility_clip == p_ignore) {
+ return;
+ }
data.disable_visibility_clip = p_ignore;
- update();
+ queue_redraw();
}
bool Control::is_visibility_clip_disabled() const {
@@ -2192,8 +2275,11 @@ bool Control::is_visibility_clip_disabled() const {
}
void Control::set_clip_contents(bool p_clip) {
+ if (data.clip_contents == p_clip) {
+ return;
+ }
data.clip_contents = p_clip;
- update();
+ queue_redraw();
}
bool Control::is_clipping_contents() {
@@ -2202,64 +2288,40 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
- Control *c = Object::cast_to<Control>(p_at);
-
- if (c && c != p_owner && c->data.theme.is_valid()) { // has a theme, this can't be propagated
- return;
- }
-
- Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
-
- if (w && w != p_owner_window && w->theme.is_valid()) { // has a theme, this can't be propagated
- return;
+void Control::_theme_changed() {
+ if (is_inside_tree()) {
+ data.theme_owner->propagate_theme_changed(this, this, true, false);
}
+}
- for (int i = 0; i < p_at->get_child_count(); i++) {
- CanvasItem *child = Object::cast_to<CanvasItem>(p_at->get_child(i));
- if (child) {
- _propagate_theme_changed(child, p_owner, p_owner_window, p_assign);
- } else {
- Window *window = Object::cast_to<Window>(p_at->get_child(i));
- if (window) {
- _propagate_theme_changed(window, p_owner, p_owner_window, p_assign);
- }
- }
+void Control::_notify_theme_override_changed() {
+ if (!data.bulk_theme_override && is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
}
+}
- if (c) {
- if (p_assign) {
- c->data.theme_owner = p_owner;
- c->data.theme_owner_window = p_owner_window;
- }
- c->notification(Control::NOTIFICATION_THEME_CHANGED);
- c->emit_signal(SceneStringNames::get_singleton()->theme_changed);
- }
+void Control::_invalidate_theme_cache() {
+ data.theme_icon_cache.clear();
+ data.theme_style_cache.clear();
+ data.theme_font_cache.clear();
+ data.theme_font_size_cache.clear();
+ data.theme_color_cache.clear();
+ data.theme_constant_cache.clear();
+}
- if (w) {
- if (p_assign) {
- w->theme_owner = p_owner;
- w->theme_owner_window = p_owner_window;
- }
- w->notification(Window::NOTIFICATION_THEME_CHANGED);
- w->emit_signal(SceneStringNames::get_singleton()->theme_changed);
- }
+void Control::_update_theme_item_cache() {
}
-void Control::_theme_changed() {
- _propagate_theme_changed(this, this, nullptr, false);
+void Control::set_theme_owner_node(Node *p_node) {
+ data.theme_owner->set_owner_node(p_node);
}
-void Control::_theme_property_override_changed() {
- notification(NOTIFICATION_THEME_CHANGED);
- emit_signal(SceneStringNames::get_singleton()->theme_changed);
- update_minimum_size(); // Overrides are likely to affect minimum size.
+Node *Control::get_theme_owner_node() const {
+ return data.theme_owner->get_owner_node();
}
-void Control::_notify_theme_changed() {
- if (!data.bulk_theme_override) {
- notification(NOTIFICATION_THEME_CHANGED);
- }
+bool Control::has_theme_owner_node() const {
+ return data.theme_owner->has_owner_node();
}
void Control::set_theme(const Ref<Theme> &p_theme) {
@@ -2272,28 +2334,25 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
data.theme = p_theme;
- if (!p_theme.is_null()) {
- data.theme_owner = this;
- data.theme_owner_window = nullptr;
- _propagate_theme_changed(this, this, nullptr);
- } else {
- Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (data.theme.is_valid()) {
+ data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
+ data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ return;
+ }
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
- } else {
- Control::_propagate_theme_changed(this, nullptr, nullptr);
- }
- }
+ Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
- if (data.theme.is_valid()) {
- data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
+
+ data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2301,8 +2360,13 @@ Ref<Theme> Control::get_theme() const {
}
void Control::set_theme_type_variation(const StringName &p_theme_type) {
+ if (data.theme_type_variation == p_theme_type) {
+ return;
+ }
data.theme_type_variation = p_theme_type;
- _propagate_theme_changed(this, data.theme_owner, data.theme_owner_window);
+ if (is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
+ }
}
StringName Control::get_theme_type_variation() const {
@@ -2311,130 +2375,6 @@ StringName Control::get_theme_type_variation() const {
/// Theme property lookup.
-template <class T>
-T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E);
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E);
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_default()->get_theme_item(p_data_type, p_name, E);
- }
- }
- // If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
-}
-
-bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- return false;
-}
-
-void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- } else {
- Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- }
- } else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
- }
-}
-
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
@@ -2443,9 +2383,15 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
}
+ if (data.theme_icon_cache.has(p_theme_type) && data.theme_icon_cache[p_theme_type].has(p_name)) {
+ return data.theme_icon_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_icon_cache[p_theme_type][p_name] = icon;
+ return icon;
}
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2456,9 +2402,15 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
}
+ if (data.theme_style_cache.has(p_theme_type) && data.theme_style_cache[p_theme_type].has(p_name)) {
+ return data.theme_style_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_style_cache[p_theme_type][p_name] = style;
+ return style;
}
Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2469,9 +2421,15 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
}
+ if (data.theme_font_cache.has(p_theme_type) && data.theme_font_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_font_cache[p_theme_type][p_name] = font;
+ return font;
}
int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2482,9 +2440,15 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
}
+ if (data.theme_font_size_cache.has(p_theme_type) && data.theme_font_size_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_size_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_font_size_cache[p_theme_type][p_name] = font_size;
+ return font_size;
}
Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2495,9 +2459,15 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
}
+ if (data.theme_color_cache.has(p_theme_type) && data.theme_color_cache[p_theme_type].has(p_name)) {
+ return data.theme_color_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_color_cache[p_theme_type][p_name] = color;
+ return color;
}
int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2508,9 +2478,15 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
}
+ if (data.theme_constant_cache.has(p_theme_type) && data.theme_constant_cache[p_theme_type].has(p_name)) {
+ return data.theme_constant_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_constant_cache[p_theme_type][p_name] = constant;
+ return constant;
}
bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2521,8 +2497,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2533,8 +2509,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2545,8 +2521,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2557,8 +2533,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2569,8 +2545,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2581,8 +2557,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
/// Local property overrides.
@@ -2591,93 +2567,93 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
ERR_FAIL_COND(!p_icon.is_valid());
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override[p_name] = p_icon;
- data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
ERR_FAIL_COND(!p_style.is_valid());
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override[p_name] = p_style;
- data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
ERR_FAIL_COND(!p_font.is_valid());
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override[p_name] = p_font;
- data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_size_override(const StringName &p_name, int p_font_size) {
data.font_size_override[p_name] = p_font_size;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) {
data.color_override[p_name] = p_color;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_constant_override(const StringName &p_name, int p_constant) {
data.constant_override[p_name] = p_constant;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_icon_override(const StringName &p_name) {
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_style_override(const StringName &p_name) {
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_override(const StringName &p_name) {
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_size_override(const StringName &p_name) {
data.font_size_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_color_override(const StringName &p_name) {
data.color_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_constant_override(const StringName &p_name) {
data.constant_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
bool Control::has_theme_icon_override(const StringName &p_name) const {
@@ -2712,157 +2688,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
/// Default theme properties.
-float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_base_scale()) {
- return theme_owner->data.theme->get_default_base_scale();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) {
- return theme_owner_window->theme->get_default_base_scale();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_base_scale()) {
- return Theme::get_project_default()->get_default_base_scale();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_base_scale()) {
- return Theme::get_default()->get_default_base_scale();
- }
- return Theme::get_fallback_base_scale();
-}
-
float Control::get_theme_default_base_scale() const {
- return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
-}
-
-Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font()) {
- return theme_owner->data.theme->get_default_font();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font()) {
- return theme_owner_window->theme->get_default_font();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font()) {
- return Theme::get_project_default()->get_default_font();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font()) {
- return Theme::get_default()->get_default_font();
- }
- return Theme::get_fallback_font();
+ return data.theme_owner->get_theme_default_base_scale();
}
Ref<Font> Control::get_theme_default_font() const {
- return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
-}
-
-int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font_size()) {
- return theme_owner->data.theme->get_default_font_size();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) {
- return theme_owner_window->theme->get_default_font_size();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font_size()) {
- return Theme::get_project_default()->get_default_font_size();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font_size()) {
- return Theme::get_default()->get_default_font_size();
- }
- return Theme::get_fallback_font_size();
+ return data.theme_owner->get_theme_default_font();
}
int Control::get_theme_default_font_size() const {
- return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+ return data.theme_owner->get_theme_default_font_size();
}
/// Bulk actions.
@@ -2875,25 +2710,25 @@ void Control::end_bulk_theme_override() {
ERR_FAIL_COND(!data.bulk_theme_override);
data.bulk_theme_override = false;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
// Internationalization.
-Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
- Array ret;
- if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) {
- return ret;
- } else {
- return Array();
- }
+ TypedArray<Vector2i> ret;
+ GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
+ return ret;
} else {
return TS->parse_structured_text(p_parser_type, p_args, p_text);
}
}
void Control::set_layout_direction(Control::LayoutDirection p_direction) {
+ if (data.layout_dir == p_direction) {
+ return;
+ }
ERR_FAIL_INDEX((int)p_direction, 4);
data.layout_dir = p_direction;
@@ -2954,12 +2789,12 @@ bool Control::is_auto_translating() const {
// Extra properties.
-void Control::set_tooltip(const String &p_tooltip) {
- data.tooltip = p_tooltip;
+void Control::set_tooltip_text(const String &p_hint) {
+ data.tooltip = p_hint;
update_configuration_warnings();
}
-String Control::_get_tooltip() const {
+String Control::get_tooltip_text() const {
return data.tooltip;
}
@@ -2969,44 +2804,31 @@ String Control::get_tooltip(const Point2 &p_pos) const {
Control *Control::make_custom_tooltip(const String &p_text) const {
Object *ret = nullptr;
- if (GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret)) {
- return Object::cast_to<Control>(ret);
- }
- return nullptr;
+ GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret);
+ return Object::cast_to<Control>(ret);
}
// Base object overrides.
-void Control::add_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && child_c->data.theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_c, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && child_w->theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_w, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-}
-
-void Control::remove_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
+void Control::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
- if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
- _propagate_theme_changed(child_c, nullptr, nullptr);
- }
+ case NOTIFICATION_PARENTED: {
+ data.theme_owner->assign_theme_on_parented(this);
+ } break;
- Window *child_w = Object::cast_to<Window>(p_child);
+ case NOTIFICATION_UNPARENTED: {
+ data.theme_owner->clear_theme_on_unparented(this);
+ } break;
- if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
- _propagate_theme_changed(child_w, nullptr, nullptr);
- }
-}
+ case NOTIFICATION_ENTER_TREE: {
+ notification(NOTIFICATION_THEME_CHANGED);
+ } break;
-void Control::_notification(int p_notification) {
- switch (p_notification) {
case NOTIFICATION_POST_ENTER_TREE: {
data.minimum_size_valid = false;
data.is_rtl_dirty = true;
@@ -3020,7 +2842,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_READY: {
#ifdef DEBUG_ENABLED
- connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONESHOT);
+ connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT);
#endif
} break;
@@ -3029,18 +2851,6 @@ void Control::_notification(int p_notification) {
data.parent_window = Object::cast_to<Window>(get_parent());
data.is_rtl_dirty = true;
- if (data.theme.is_null()) {
- if (data.parent && (data.parent->data.theme_owner || data.parent->data.theme_owner_window)) {
- data.theme_owner = data.parent->data.theme_owner;
- data.theme_owner_window = data.parent->data.theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- } else if (data.parent_window && (data.parent_window->theme_owner || data.parent_window->theme_owner_window)) {
- data.theme_owner = data.parent_window->theme_owner;
- data.theme_owner_window = data.parent_window->theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- }
-
CanvasItem *node = this;
bool has_parent_control = false;
@@ -3084,8 +2894,8 @@ void Control::_notification(int p_notification) {
if (data.parent_canvas_item) {
data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed));
data.parent_canvas_item = nullptr;
- } else if (!is_set_as_top_level()) {
- //disconnect viewport
+ } else {
+ // Disconnect viewport.
Viewport *viewport = get_viewport();
ERR_FAIL_COND(!viewport);
viewport->disconnect("size_changed", callable_mp(this, &Control::_size_changed));
@@ -3106,9 +2916,9 @@ void Control::_notification(int p_notification) {
// some parents need to know the order of the children to draw (like TabContainer)
// update if necessary
if (data.parent) {
- data.parent->update();
+ data.parent->queue_redraw();
}
- update();
+ queue_redraw();
if (data.RI) {
get_viewport()->_gui_set_root_order_dirty();
@@ -3135,17 +2945,20 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_FOCUS_ENTER: {
emit_signal(SceneStringNames::get_singleton()->focus_entered);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_EXIT: {
emit_signal(SceneStringNames::get_singleton()->focus_exited);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -3164,6 +2977,8 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
_size_changed();
}
} break;
@@ -3291,9 +3106,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_grow_direction", "direction"), &Control::set_v_grow_direction);
ClassDB::bind_method(D_METHOD("get_v_grow_direction"), &Control::get_v_grow_direction);
- ClassDB::bind_method(D_METHOD("set_tooltip", "tooltip"), &Control::set_tooltip);
+ ClassDB::bind_method(D_METHOD("set_tooltip_text", "hint"), &Control::set_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_tooltip_text"), &Control::get_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip", "at_position"), &Control::get_tooltip, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("_get_tooltip"), &Control::_get_tooltip);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Control::set_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
@@ -3327,6 +3142,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse);
+ ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context);
+ ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context);
+
ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size);
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Control::set_layout_direction);
@@ -3340,7 +3158,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
const String anchors_presets_options = "Custom:-1,PresetFullRect:15,"
@@ -3348,14 +3166,14 @@ void Control::_bind_methods() {
"PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8,"
"PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14";
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
ADD_SUBGROUP_INDENT("Anchor Offsets", "offset_", 1);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_LEFT);
@@ -3371,7 +3189,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset");
@@ -3383,8 +3201,8 @@ void Control::_bind_methods() {
ADD_GROUP("Auto Translate", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating");
- ADD_GROUP("Hint", "hint_");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
+ ADD_GROUP("Tooltip", "tooltip_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tooltip_text", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip_text", "get_tooltip_text");
ADD_GROUP("Focus", "focus_");
ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_LEFT);
@@ -3400,6 +3218,9 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
+ ADD_GROUP("Input", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+
ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
@@ -3507,3 +3328,30 @@ void Control::_bind_methods() {
GDVIRTUAL_BIND(_gui_input, "event");
}
+
+Control::Control() {
+ data.theme_owner = memnew(ThemeOwner);
+}
+
+Control::~Control() {
+ memdelete(data.theme_owner);
+
+ // Resources need to be disconnected.
+ for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<StyleBox>> &E : data.style_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<Font>> &E : data.font_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+
+ // Then override maps can be simply cleared.
+ data.icon_override.clear();
+ data.style_override.clear();
+ data.font_override.clear();
+ data.font_size_override.clear();
+ data.color_override.clear();
+ data.constant_override.clear();
+}