diff options
Diffstat (limited to 'scene/main/window.cpp')
-rw-r--r-- | scene/main/window.cpp | 303 |
1 files changed, 202 insertions, 101 deletions
diff --git a/scene/main/window.cpp b/scene/main/window.cpp index bf50ca0956..64869b2936 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -32,9 +32,13 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" +#include "core/input/shortcut.h" #include "core/string/translation.h" +#include "core/variant/variant_parser.h" #include "scene/gui/control.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" +#include "scene/theme/theme_owner.h" void Window::set_title(const String &p_title) { title = p_title; @@ -385,9 +389,24 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE); emit_signal(SNAME("dpi_changed")); } break; + case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: { + emit_signal(SNAME("titlebar_changed")); + } break; } } +void Window::update_mouse_cursor_shape() { + // The default shape is set in Viewport::_gui_input_event. To instantly + // see the shape in the viewport we need to trigger a mouse motion event. + Ref<InputEventMouseMotion> mm; + Vector2 pos = get_mouse_position(); + Transform2D xform = get_global_canvas_transform().affine_inverse(); + mm.instantiate(); + mm->set_position(pos); + mm->set_global_position(xform.xform(pos)); + push_input(mm); +} + void Window::show() { set_visible(true); } @@ -796,6 +815,19 @@ Viewport *Window::_get_embedder() const { void Window::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + _invalidate_theme_cache(); + _update_theme_item_cache(); + } break; + + case NOTIFICATION_PARENTED: { + theme_owner->assign_theme_on_parented(this); + } break; + + case NOTIFICATION_UNPARENTED: { + theme_owner->clear_theme_on_unparented(this); + } break; + case NOTIFICATION_ENTER_TREE: { bool embedded = false; { @@ -848,21 +880,13 @@ void Window::_notification(int p_what) { RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); } - if (theme.is_null()) { - Control *parent_c = cast_to<Control>(get_parent()); - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } else { - Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } - } - } + notification(NOTIFICATION_THEME_CHANGED); + } break; + + case NOTIFICATION_THEME_CHANGED: { + emit_signal(SceneStringNames::get_singleton()->theme_changed); + _invalidate_theme_cache(); + _update_theme_item_cache(); } break; case NOTIFICATION_READY: { @@ -872,6 +896,9 @@ void Window::_notification(int p_what) { } break; case NOTIFICATION_TRANSLATION_CHANGED: { + _invalidate_theme_cache(); + _update_theme_item_cache(); + if (embedder) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { @@ -1029,9 +1056,31 @@ bool Window::_can_consume_input_events() const { void Window::_window_input(const Ref<InputEvent> &p_ev) { if (EngineDebugger::is_active()) { - // Quit from game window using F8. + // Quit from game window using the stop shortcut (F8 by default). + // The custom shortcut is provided via environment variable when running from the editor. + if (debugger_stop_shortcut.is_null()) { + String shortcut_str = OS::get_singleton()->get_environment("__GODOT_EDITOR_STOP_SHORTCUT__"); + if (!shortcut_str.is_empty()) { + Variant shortcut_var; + + VariantParser::StreamString ss; + ss.s = shortcut_str; + + String errs; + int line; + VariantParser::parse(&ss, shortcut_var, errs, line); + debugger_stop_shortcut = shortcut_var; + } + + if (debugger_stop_shortcut.is_null()) { + // Define a default shortcut if it wasn't provided or is invalid. + debugger_stop_shortcut.instantiate(); + debugger_stop_shortcut->set_events({ (Variant)InputEventKey::create_reference(Key::F8) }); + } + } + Ref<InputEventKey> k = p_ev; - if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::F8) { + if (k.is_valid() && k->is_pressed() && !k->is_echo() && debugger_stop_shortcut->matches_event(k)) { EngineDebugger::get_singleton()->send_message("request_quit", Array()); } } @@ -1107,7 +1156,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); @@ -1133,7 +1182,7 @@ void Window::popup_centered(const Size2i &p_minsize) { Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); @@ -1161,7 +1210,7 @@ void Window::popup_centered_ratio(float p_ratio) { Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); @@ -1214,6 +1263,15 @@ void Window::popup(const Rect2i &p_screen_rect) { set_transient(true); set_visible(true); + + int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id()); + Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id); + if (screen_rect != Rect2i() && !screen_rect.intersects(Rect2i(position, size))) { + ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position)); + // Window appeared on unavailable screen area, so force it to the center. + set_position(screen_rect.size / 2 - size / 2); + } + _post_popup(); notification(NOTIFICATION_POST_POPUP); } @@ -1250,39 +1308,27 @@ Rect2i Window::get_usable_parent_rect() const { } void Window::add_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) { - Control::_propagate_theme_changed(child_c, theme_owner, 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() && (theme_owner || theme_owner_window)) { - Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff - } - if (is_inside_tree() && wrap_controls) { child_controls_changed(); } } void Window::remove_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) { - Control::_propagate_theme_changed(child_c, nullptr, nullptr); + if (is_inside_tree() && wrap_controls) { + child_controls_changed(); } +} - Window *child_w = Object::cast_to<Window>(p_child); +void Window::set_theme_owner_node(Node *p_node) { + theme_owner->set_owner_node(p_node); +} - if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { - Control::_propagate_theme_changed(child_w, nullptr, nullptr); - } +Node *Window::get_theme_owner_node() const { + return theme_owner->get_owner_node(); +} - if (is_inside_tree() && wrap_controls) { - child_controls_changed(); - } +bool Window::has_theme_owner_node() const { + return theme_owner->has_owner_node(); } void Window::set_theme(const Ref<Theme> &p_theme) { @@ -1290,134 +1336,183 @@ void Window::set_theme(const Ref<Theme> &p_theme) { return; } + if (theme.is_valid()) { + theme->disconnect("changed", callable_mp(this, &Window::_theme_changed)); + } + theme = p_theme; + if (theme.is_valid()) { + theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true); + theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED); + return; + } - if (!p_theme.is_null()) { - theme_owner = nullptr; - theme_owner_window = this; - Control::_propagate_theme_changed(this, nullptr, this); - } else { - Control *parent_c = cast_to<Control>(get_parent()); - 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()) { + theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true); + return; } + + Window *parent_w = cast_to<Window>(get_parent()); + if (parent_w && parent_w->has_theme_owner_node()) { + theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true); + return; + } + + theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true); } Ref<Theme> Window::get_theme() const { return theme; } +void Window::_theme_changed() { + if (is_inside_tree()) { + theme_owner->propagate_theme_changed(this, this, true, false); + } +} + +void Window::_invalidate_theme_cache() { + theme_icon_cache.clear(); + theme_style_cache.clear(); + theme_font_cache.clear(); + theme_font_size_cache.clear(); + theme_color_cache.clear(); + theme_constant_cache.clear(); +} + +void Window::_update_theme_item_cache() { +} + void Window::set_theme_type_variation(const StringName &p_theme_type) { theme_type_variation = p_theme_type; - Control::_propagate_theme_changed(this, theme_owner, theme_owner_window); + if (is_inside_tree()) { + notification(NOTIFICATION_THEME_CHANGED); + } } StringName Window::get_theme_type_variation() const { return theme_type_variation; } -void Window::_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 == theme_type_variation) { - if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(theme_type_variation) != StringName()) { - Theme::get_project_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); - } else { - Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); - } - } else { - Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list); +Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) { + return theme_icon_cache[p_theme_type][p_name]; } -} -Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_icon_cache[p_theme_type][p_name] = icon; + return icon; } Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_style_cache.has(p_theme_type) && theme_style_cache[p_theme_type].has(p_name)) { + return theme_style_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<StyleBox> style = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_style_cache[p_theme_type][p_name] = style; + return style; } Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_font_cache.has(p_theme_type) && theme_font_cache[p_theme_type].has(p_name)) { + return theme_font_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Font> font = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_font_cache[p_theme_type][p_name] = font; + return font; } int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_font_size_cache.has(p_theme_type) && theme_font_size_cache[p_theme_type].has(p_name)) { + return theme_font_size_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int font_size = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_font_size_cache[p_theme_type][p_name] = font_size; + return font_size; } Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_color_cache.has(p_theme_type) && theme_color_cache[p_theme_type].has(p_name)) { + return theme_color_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Color color = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_color_cache[p_theme_type][p_name] = color; + return color; } int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_constant_cache.has(p_theme_type) && theme_constant_cache[p_theme_type].has(p_name)) { + return theme_constant_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int constant = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_constant_cache[p_theme_type][p_name] = constant; + return constant; } bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); } bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); } bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); } bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); } bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); } bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } float Window::get_theme_default_base_scale() const { - return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_base_scale(); } Ref<Font> Window::get_theme_default_font() const { - return Control::fetch_theme_default_font(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_font(); } int Window::get_theme_default_font_size() const { - return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_font_size(); } Rect2i Window::get_parent_rect() const { @@ -1518,9 +1613,9 @@ void Window::_validate_property(PropertyInfo &p_property) const { // 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>(); @@ -1681,6 +1776,7 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE); ADD_GROUP("Limits", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size"); @@ -1710,8 +1806,10 @@ void Window::_bind_methods() { ADD_SIGNAL(MethodInfo("visibility_changed")); ADD_SIGNAL(MethodInfo("about_to_popup")); ADD_SIGNAL(MethodInfo("theme_changed")); + ADD_SIGNAL(MethodInfo("titlebar_changed")); BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); + BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); BIND_ENUM_CONSTANT(MODE_WINDOWED); BIND_ENUM_CONSTANT(MODE_MINIMIZED); @@ -1725,6 +1823,7 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_TRANSPARENT); BIND_ENUM_CONSTANT(FLAG_NO_FOCUS); BIND_ENUM_CONSTANT(FLAG_POPUP); + BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); @@ -1744,8 +1843,10 @@ void Window::_bind_methods() { } Window::Window() { + theme_owner = memnew(ThemeOwner); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); } Window::~Window() { + memdelete(theme_owner); } |