diff options
Diffstat (limited to 'scene')
76 files changed, 4779 insertions, 3370 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 3ef4dfe5f1..df0b17800f 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -32,7 +32,7 @@ #include "core/engine.h" #include "scene/2d/area_2d.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" void AudioStreamPlayer2D::_mix_audio() { diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 04b5260444..7a106ef79a 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -32,7 +32,7 @@ #define CAMERA_2D_H #include "scene/2d/node_2d.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" class Camera2D : public Node2D { diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index ef7aa9ba01..7a0fc3352b 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -29,11 +29,13 @@ /*************************************************************************/ #include "canvas_item.h" + +#include "core/input/input_filter.h" #include "core/message_queue.h" #include "core/method_bind_ext.gen.inc" -#include "core/os/input.h" #include "scene/main/canvas_layer.h" #include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/font.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" @@ -347,6 +349,9 @@ bool CanvasItem::is_visible_in_tree() const { while (p) { if (!p->visible) return false; + if (p->window && !p->window->is_visible()) { + return false; + } p = p->get_parent_item(); } @@ -450,6 +455,21 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const { return get_global_transform(); } +Transform2D CanvasItem::get_screen_transform() const { + ERR_FAIL_COND_V(!is_inside_tree(), Transform2D()); + Transform2D xform = get_global_transform_with_canvas(); + + Window *w = Object::cast_to<Window>(get_viewport()); + if (w && !w->is_embedding_subwindows()) { + Transform2D s; + s.set_origin(w->get_position()); + + xform = s * xform; + } + + return xform; +} + Transform2D CanvasItem::get_global_transform() const { #ifdef DEBUG_ENABLED ERR_FAIL_COND_V(!is_inside_tree(), get_transform()); @@ -548,10 +568,30 @@ void CanvasItem::_notification(int p_what) { _update_texture_repeat_changed(false); first_draw = true; - if (get_parent()) { - CanvasItem *ci = Object::cast_to<CanvasItem>(get_parent()); + Node *parent = get_parent(); + if (parent) { + CanvasItem *ci = Object::cast_to<CanvasItem>(parent); if (ci) C = ci->children_items.push_back(this); + if (!ci) { + //look for a window + Viewport *viewport = nullptr; + + while (parent) { + viewport = Object::cast_to<Viewport>(parent); + if (viewport) { + break; + } + parent = parent->get_parent(); + } + + ERR_FAIL_COND(!viewport); + + window = Object::cast_to<Window>(viewport); + if (window) { + window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); + } + } } _enter_canvas(); if (!block_transform_notify && !xform_change.in_list()) { @@ -580,6 +620,9 @@ void CanvasItem::_notification(int p_what) { Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C); C = NULL; } + if (window) { + window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); + } global_invalid = true; } break; case NOTIFICATION_DRAW: @@ -600,6 +643,14 @@ void CanvasItem::set_visible(bool p_visible) { else hide(); } + +void CanvasItem::_window_visibility_changed() { + + if (visible) { + _propagate_visibility_changed(window->is_visible()); + } +} + bool CanvasItem::is_visible() const { return visible; @@ -1408,6 +1459,7 @@ CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const { CanvasItem::CanvasItem() : xform_change(this) { + window = nullptr; canvas_item = VisualServer::get_singleton()->canvas_item_create(); visible = true; pending_update = false; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index c7f9500ea1..3f176e5f60 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -201,6 +201,7 @@ private: int light_mask; + Window *window; bool first_draw; bool visible; bool pending_update; @@ -232,6 +233,8 @@ private: void _enter_canvas(); void _exit_canvas(); + void _window_visibility_changed(); + void _notify_transform(CanvasItem *p_node); void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } @@ -364,6 +367,7 @@ public: virtual Transform2D get_global_transform() const; virtual Transform2D get_global_transform_with_canvas() const; + virtual Transform2D get_screen_transform() const; CanvasItem *get_toplevel() const; _FORCE_INLINE_ RID get_canvas_item() const { diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index df21538609..0b0b9820d3 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -32,7 +32,7 @@ #include "core/message_queue.h" #include "scene/gui/control.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "servers/visual_server.h" #ifdef TOOLS_ENABLED diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 2ba2fd8f79..e5c17fe9a4 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -228,7 +228,7 @@ bool Particles2D::get_fractional_delta() const { String Particles2D::get_configuration_warning() const { - if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + if (VisualServer::get_singleton()->is_low_end()) { return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); } diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 7eaafe5348..a6fb6f7435 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/os/os.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" #ifdef TOOLS_ENABLED diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 1cca45b422..2cb979a0e0 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -30,10 +30,11 @@ #include "touch_screen_button.h" -#include "core/input_map.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" +#include "core/input/input_map.h" #include "core/os/os.h" - +#include "scene/main/window.h" +# void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; @@ -114,7 +115,7 @@ void TouchScreenButton::_notification(int p_what) { if (!is_inside_tree()) return; - if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) + if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) return; if (finger_pressed != -1) { @@ -145,7 +146,7 @@ void TouchScreenButton::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) + if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) return; update(); @@ -289,12 +290,12 @@ void TouchScreenButton::_press(int p_finger_pressed) { if (action != StringName()) { - Input::get_singleton()->action_press(action); + InputFilter::get_singleton()->action_press(action); Ref<InputEventAction> iea; iea.instance(); iea->set_action(action); iea->set_pressed(true); - get_tree()->input_event(iea); + get_viewport()->input(iea, true); } emit_signal("pressed"); @@ -307,14 +308,14 @@ void TouchScreenButton::_release(bool p_exiting_tree) { if (action != StringName()) { - Input::get_singleton()->action_release(action); + InputFilter::get_singleton()->action_release(action); if (!p_exiting_tree) { Ref<InputEventAction> iea; iea.instance(); iea->set_action(action); iea->set_pressed(false); - get_tree()->input_event(iea); + get_viewport()->input(iea, true); } } diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 54511bbe1b..65dabb92b1 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -35,7 +35,7 @@ #include "scene/2d/animated_sprite.h" #include "scene/2d/physics_body_2d.h" #include "scene/animation/animation_player.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" #ifdef TOOLS_ENABLED diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index d23e5ffa08..bea717b354 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "arvr_nodes.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" #include "servers/arvr/arvr_interface.h" #include "servers/arvr_server.h" @@ -206,7 +206,7 @@ void ARVRController::_notification(int p_what) { // check button states for (int i = 0; i < 16; i++) { bool was_pressed = (button_states & mask) == mask; - bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, i); + bool is_pressed = InputFilter::get_singleton()->is_joy_button_pressed(joy_id, i); if (!was_pressed && is_pressed) { emit_signal("button_pressed", i); @@ -306,7 +306,7 @@ bool ARVRController::is_button_pressed(int p_button) const { return false; }; - return Input::get_singleton()->is_joy_button_pressed(joy_id, p_button); + return InputFilter::get_singleton()->is_joy_button_pressed(joy_id, p_button); }; float ARVRController::get_joystick_axis(int p_axis) const { @@ -315,7 +315,7 @@ float ARVRController::get_joystick_axis(int p_axis) const { return 0.0; }; - return Input::get_singleton()->get_joy_axis(joy_id, p_axis); + return InputFilter::get_singleton()->get_joy_axis(joy_id, p_axis); }; real_t ARVRController::get_rumble() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index f0a61a905c..f3020d4044 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -33,7 +33,7 @@ #include "scene/3d/area.h" #include "scene/3d/camera.h" #include "scene/3d/listener.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" // Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004) // Speaker-Placement Correction Amplitude Panning (SPCAP) diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 6ac3ece798..feb7b39b1e 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -33,7 +33,7 @@ #include "scene/3d/spatial.h" #include "scene/3d/spatial_velocity_tracker.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/environment.h" class Camera : public Spatial { diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index c3f039ae85..76549f7e51 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -526,7 +526,7 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { String GIProbe::get_configuration_warning() const { - if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + if (VisualServer::get_singleton()->is_low_end()) { return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); } return String(); diff --git a/scene/3d/listener.h b/scene/3d/listener.h index 287e67f31e..17ff1d9397 100644 --- a/scene/3d/listener.h +++ b/scene/3d/listener.h @@ -32,7 +32,7 @@ #define LISTENER_H #include "scene/3d/spatial.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" class Listener : public Spatial { diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index e502b0c037..7a1eeb105a 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -240,7 +240,7 @@ bool Particles::get_fractional_delta() const { String Particles::get_configuration_warning() const { - if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + if (VisualServer::get_singleton()->is_low_end()) { return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); } diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index f1911348ce..c6225dd291 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -33,7 +33,7 @@ #include "core/engine.h" #include "core/message_queue.h" #include "scene/main/scene_tree.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" /* diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 83a7243906..9276432ba9 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "world_environment.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" void WorldEnvironment::_notification(int p_what) { diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index 7a184adc55..359f936793 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -34,7 +34,7 @@ #include "core/io/marshalls.h" #include "core/script_language.h" #include "scene/main/scene_tree.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/packed_scene.h" void SceneDebugger::initialize() { diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index b2020d44e8..a05ac08e9d 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -31,7 +31,7 @@ #include "base_button.h" #include "core/os/keyboard.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" void BaseButton::_unpress_group() { @@ -357,9 +357,6 @@ void BaseButton::_unhandled_input(Ref<InputEvent> p_event) { if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { - if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)) - return; //ignore because of modal window - on_action_event(p_event); } } diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index e0bfeac9f7..0da6e0fdfa 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -45,7 +45,7 @@ void BoxContainer::_resort() { Size2i new_size = get_size(); - int sep = get_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); + int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); bool first = true; int children_count = 0; @@ -206,7 +206,7 @@ Size2 BoxContainer::get_minimum_size() const { /* Calculate MINIMUM SIZE */ Size2i minimum; - int sep = get_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); + int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); bool first = true; @@ -310,7 +310,7 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control l->set_text(p_label); add_child(l); MarginContainer *mc = memnew(MarginContainer); - mc->add_constant_override("margin_left", 0); + mc->add_theme_constant_override("margin_left", 0); mc->add_child(p_control); add_child(mc); if (p_expand) diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 784d298bff..f71d322412 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -35,14 +35,14 @@ Size2 Button::get_minimum_size() const { - Size2 minsize = get_font("font")->get_string_size(xl_text); + Size2 minsize = get_theme_font("font")->get_string_size(xl_text); if (clip_text) minsize.width = 0; if (!expand_icon) { Ref<Texture2D> _icon; - if (icon.is_null() && has_icon("icon")) - _icon = Control::get_icon("icon"); + if (icon.is_null() && has_theme_icon("icon")) + _icon = Control::get_theme_icon("icon"); else _icon = icon; @@ -51,11 +51,11 @@ Size2 Button::get_minimum_size() const { minsize.height = MAX(minsize.height, _icon->get_height()); minsize.width += _icon->get_width(); if (xl_text != "") - minsize.width += get_constant("hseparation"); + minsize.width += get_theme_constant("hseparation"); } } - return get_stylebox("normal")->get_minimum_size() + minsize; + return get_theme_stylebox("normal")->get_minimum_size() + minsize; } void Button::_set_internal_margin(Margin p_margin, float p_value) { @@ -79,30 +79,30 @@ void Button::_notification(int p_what) { Color color; Color color_icon(1, 1, 1, 1); - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); switch (get_draw_mode()) { case DRAW_NORMAL: { - style = get_stylebox("normal"); + style = get_theme_stylebox("normal"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color"); - if (has_color("icon_color_normal")) - color_icon = get_color("icon_color_normal"); + color = get_theme_color("font_color"); + if (has_theme_color("icon_color_normal")) + color_icon = get_theme_color("icon_color_normal"); } break; case DRAW_HOVER_PRESSED: { - if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) { - style = get_stylebox("hover_pressed"); + if (has_theme_stylebox("hover_pressed") && has_theme_stylebox_override("hover_pressed")) { + style = get_theme_stylebox("hover_pressed"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - if (has_color("font_color_hover_pressed")) - color = get_color("font_color_hover_pressed"); + if (has_theme_color("font_color_hover_pressed")) + color = get_theme_color("font_color_hover_pressed"); else - color = get_color("font_color"); - if (has_color("icon_color_hover_pressed")) - color_icon = get_color("icon_color_hover_pressed"); + color = get_theme_color("font_color"); + if (has_theme_color("icon_color_hover_pressed")) + color_icon = get_theme_color("icon_color_hover_pressed"); break; } @@ -110,49 +110,49 @@ void Button::_notification(int p_what) { } case DRAW_PRESSED: { - style = get_stylebox("pressed"); + style = get_theme_stylebox("pressed"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - if (has_color("font_color_pressed")) - color = get_color("font_color_pressed"); + if (has_theme_color("font_color_pressed")) + color = get_theme_color("font_color_pressed"); else - color = get_color("font_color"); - if (has_color("icon_color_pressed")) - color_icon = get_color("icon_color_pressed"); + color = get_theme_color("font_color"); + if (has_theme_color("icon_color_pressed")) + color_icon = get_theme_color("icon_color_pressed"); } break; case DRAW_HOVER: { - style = get_stylebox("hover"); + style = get_theme_stylebox("hover"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color_hover"); - if (has_color("icon_color_hover")) - color_icon = get_color("icon_color_hover"); + color = get_theme_color("font_color_hover"); + if (has_theme_color("icon_color_hover")) + color_icon = get_theme_color("icon_color_hover"); } break; case DRAW_DISABLED: { - style = get_stylebox("disabled"); + style = get_theme_stylebox("disabled"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color_disabled"); - if (has_color("icon_color_disabled")) - color_icon = get_color("icon_color_disabled"); + color = get_theme_color("font_color_disabled"); + if (has_theme_color("icon_color_disabled")) + color_icon = get_theme_color("icon_color_disabled"); } break; } if (has_focus()) { - Ref<StyleBox> style2 = get_stylebox("focus"); + Ref<StyleBox> style2 = get_theme_stylebox("focus"); style2->draw(ci, Rect2(Point2(), size)); } - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); Ref<Texture2D> _icon; - if (icon.is_null() && has_icon("icon")) - _icon = Control::get_icon("icon"); + if (icon.is_null() && has_theme_icon("icon")) + _icon = Control::get_theme_icon("icon"); else _icon = icon; @@ -166,14 +166,14 @@ void Button::_notification(int p_what) { float icon_ofs_region = 0; if (_internal_margin[MARGIN_LEFT] > 0) { - icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); + icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); } if (expand_icon) { Size2 _size = get_size() - style->get_offset() * 2; - _size.width -= get_constant("hseparation") + icon_ofs_region; + _size.width -= get_theme_constant("hseparation") + icon_ofs_region; if (!clip_text) - _size.width -= get_font("font")->get_string_size(xl_text).width; + _size.width -= get_theme_font("font")->get_string_size(xl_text).width; float icon_width = _icon->get_width() * _size.height / _icon->get_height(); float icon_height = _size.height; @@ -188,13 +188,13 @@ void Button::_notification(int p_what) { } } - Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_constant("hseparation"), 0) : Point2(); + Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant("hseparation"), 0) : Point2(); int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; if (_internal_margin[MARGIN_LEFT] > 0) { - text_clip -= _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); + text_clip -= _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); } if (_internal_margin[MARGIN_RIGHT] > 0) { - text_clip -= _internal_margin[MARGIN_RIGHT] + get_constant("hseparation"); + text_clip -= _internal_margin[MARGIN_RIGHT] + get_theme_constant("hseparation"); } Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0; @@ -202,7 +202,7 @@ void Button::_notification(int p_what) { switch (align) { case ALIGN_LEFT: { if (_internal_margin[MARGIN_LEFT] > 0) { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); + text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); } else { text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; } @@ -216,7 +216,7 @@ void Button::_notification(int p_what) { } break; case ALIGN_RIGHT: { if (_internal_margin[MARGIN_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation"); + text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_theme_constant("hseparation"); } else { text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; } diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 89bd8ab0dd..d68bd4fe4e 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -33,10 +33,10 @@ #include "servers/visual_server.h" Size2 CheckBox::get_icon_size() const { - Ref<Texture2D> checked = Control::get_icon("checked"); - Ref<Texture2D> unchecked = Control::get_icon("unchecked"); - Ref<Texture2D> radio_checked = Control::get_icon("radio_checked"); - Ref<Texture2D> radio_unchecked = Control::get_icon("radio_unchecked"); + Ref<Texture2D> checked = Control::get_theme_icon("checked"); + Ref<Texture2D> unchecked = Control::get_theme_icon("unchecked"); + Ref<Texture2D> radio_checked = Control::get_theme_icon("radio_checked"); + Ref<Texture2D> radio_unchecked = Control::get_theme_icon("radio_unchecked"); Size2 tex_size = Size2(0, 0); if (!checked.is_null()) @@ -56,9 +56,9 @@ Size2 CheckBox::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) { - minsize.width += get_constant("hseparation"); + minsize.width += get_theme_constant("hseparation"); } - Ref<StyleBox> sb = get_stylebox("normal"); + Ref<StyleBox> sb = get_theme_stylebox("normal"); minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); return minsize; @@ -73,13 +73,13 @@ void CheckBox::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<Texture2D> on = Control::get_icon(is_radio() ? "radio_checked" : "checked"); - Ref<Texture2D> off = Control::get_icon(is_radio() ? "radio_unchecked" : "unchecked"); - Ref<StyleBox> sb = get_stylebox("normal"); + Ref<Texture2D> on = Control::get_theme_icon(is_radio() ? "radio_checked" : "checked"); + Ref<Texture2D> off = Control::get_theme_icon(is_radio() ? "radio_unchecked" : "unchecked"); + Ref<StyleBox> sb = get_theme_stylebox("normal"); Vector2 ofs; ofs.x = sb->get_margin(MARGIN_LEFT); - ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_constant("check_vadjust"); + ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant("check_vadjust"); if (is_pressed()) on->draw(ci, ofs); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index 0b093ce850..ac967a128c 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -35,8 +35,8 @@ Size2 CheckButton::get_icon_size() const { - Ref<Texture2D> on = Control::get_icon(is_disabled() ? "on_disabled" : "on"); - Ref<Texture2D> off = Control::get_icon(is_disabled() ? "off_disabled" : "off"); + Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on"); + Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); Size2 tex_size = Size2(0, 0); if (!on.is_null()) tex_size = Size2(on->get_width(), on->get_height()); @@ -52,8 +52,8 @@ Size2 CheckButton::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) - minsize.width += get_constant("hseparation"); - Ref<StyleBox> sb = get_stylebox("normal"); + minsize.width += get_theme_constant("hseparation"); + Ref<StyleBox> sb = get_theme_stylebox("normal"); minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); return minsize; @@ -68,15 +68,15 @@ void CheckButton::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<Texture2D> on = Control::get_icon(is_disabled() ? "on_disabled" : "on"); - Ref<Texture2D> off = Control::get_icon(is_disabled() ? "off_disabled" : "off"); + Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on"); + Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); - Ref<StyleBox> sb = get_stylebox("normal"); + Ref<StyleBox> sb = get_theme_stylebox("normal"); Vector2 ofs; Size2 tex_size = get_icon_size(); ofs.x = get_size().width - (tex_size.width + sb->get_margin(MARGIN_RIGHT)); - ofs.y = (get_size().height - tex_size.height) / 2 + get_constant("check_vadjust"); + ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant("check_vadjust"); if (is_pressed()) on->draw(ci, ofs); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index a8b5ac6909..2ec9bb2292 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -30,7 +30,7 @@ #include "color_picker.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -38,22 +38,22 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #endif -#include "scene/main/viewport.h" +#include "scene/main/window.h" void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); - bt_add_preset->set_icon(get_icon("add_preset")); + btn_pick->set_icon(get_theme_icon("screen_picker", "ColorPicker")); + bt_add_preset->set_icon(get_theme_icon("add_preset")); _update_controls(); } break; case NOTIFICATION_ENTER_TREE: { - btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); - bt_add_preset->set_icon(get_icon("add_preset")); + btn_pick->set_icon(get_theme_icon("screen_picker", "ColorPicker")); + bt_add_preset->set_icon(get_theme_icon("add_preset")); _update_color(); @@ -70,15 +70,15 @@ void ColorPicker::_notification(int p_what) { case NOTIFICATION_PARENTED: { for (int i = 0; i < 4; i++) - set_margin((Margin)i, get_constant("margin")); + set_margin((Margin)i, get_theme_constant("margin")); } break; case NOTIFICATION_VISIBILITY_CHANGED: { Popup *p = Object::cast_to<Popup>(get_parent()); if (p) - p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2)); + p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant("margin") * 2, get_combined_minimum_size().height + get_theme_constant("margin") * 2)); } break; - case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + case NOTIFICATION_WM_CLOSE_REQUEST: { if (screen != NULL && screen->is_visible()) screen->hide(); @@ -247,6 +247,9 @@ void ColorPicker::_update_color(bool p_update_sliders) { } void ColorPicker::_update_presets() { + return; + //presets should be shown using buttons or something else, this method is not a good idea + presets_per_row = 10; Size2 size = bt_add_preset->get_size(); Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row))); @@ -267,7 +270,7 @@ void ColorPicker::_text_type_toggled() { text_is_constructor = !text_is_constructor; if (text_is_constructor) { text_type->set_text(""); - text_type->set_icon(get_icon("Script", "EditorIcons")); + text_type->set_icon(get_theme_icon("Script", "EditorIcons")); c_text->set_editable(false); } else { @@ -399,14 +402,14 @@ void ColorPicker::_sample_draw() { const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95)); if (color.a < 1.0) { - sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), r, true); + sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true); } sample->draw_rect(r, color); if (color.r > 1 || color.g > 1 || color.b > 1) { // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview - sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2()); + sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2()); } } @@ -445,7 +448,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); c->draw_line(Point2(x, y), Point2(x, y), Color(1, 1, 1), 2); } else if (p_which == 1) { - Ref<Texture2D> hue = get_icon("color_hue", "ColorPicker"); + Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker"); c->draw_texture_rect(hue, Rect2(Point2(), c->get_size())); int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col = Color(); @@ -620,7 +623,10 @@ void ColorPicker::_screen_pick_pressed() { screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false)); } screen->raise(); - screen->show_modal(); +#ifndef _MSC_VER +#warning show modal no longer works, needs to be converted to a popup +#endif + //screen->show_modal(); } void ColorPicker::_focus_enter() { @@ -738,12 +744,12 @@ ColorPicker::ColorPicker() : uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); - uv_edit->set_custom_minimum_size(Size2(get_constant("sv_width"), get_constant("sv_height"))); + uv_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height"))); uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit)); w_edit = memnew(Control); hb_edit->add_child(w_edit); - w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0)); + w_edit->set_custom_minimum_size(Size2(get_theme_constant("h_width"), 0)); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input)); @@ -777,7 +783,7 @@ ColorPicker::ColorPicker() : HBoxContainer *hbc = memnew(HBoxContainer); labels[i] = memnew(Label()); - labels[i]->set_custom_minimum_size(Size2(get_constant("label_width"), 0)); + labels[i]->set_custom_minimum_size(Size2(get_theme_constant("label_width"), 0)); labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER); hbc->add_child(labels[i]); @@ -881,8 +887,32 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { _update_picker(); - popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale()); - popup->set_scale(get_global_transform().get_scale()); + + popup->set_as_minsize(); + + Rect2i usable_rect = popup->get_usable_parent_rect(); + //let's try different positions to see which one we can use + + Rect2i cp_rect(Point2i(), popup->get_size()); + for (int i = 0; i < 4; i++) { + if (i > 1) { + cp_rect.position.y = get_screen_position().y - cp_rect.size.y; + } else { + cp_rect.position.y = get_screen_position().y + get_size().height; + } + + if (i & 1) { + cp_rect.position.x = get_screen_position().x; + } else { + + cp_rect.position.x = get_screen_position().x - MAX(0, (cp_rect.size.x - get_size().x)); + } + + if (usable_rect.encloses(cp_rect)) { + break; + } + } + popup->set_position(cp_rect.position); popup->popup(); picker->set_focus_on_line_edit(); } @@ -892,17 +922,17 @@ void ColorPickerButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { - const Ref<StyleBox> normal = get_stylebox("normal"); + const Ref<StyleBox> normal = get_theme_stylebox("normal"); const Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size()); - draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true); + draw_texture_rect(Control::get_theme_icon("bg", "ColorPickerButton"), r, true); draw_rect(r, color); if (color.r > 1 || color.g > 1 || color.b > 1) { // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview - draw_texture(Control::get_icon("overbright_indicator", "ColorPicker"), normal->get_offset()); + draw_texture(Control::get_theme_icon("overbright_indicator", "ColorPicker"), normal->get_offset()); } } break; - case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + case NOTIFICATION_WM_CLOSE_REQUEST: { if (popup) popup->hide(); @@ -958,12 +988,14 @@ PopupPanel *ColorPickerButton::get_popup() { void ColorPickerButton::_update_picker() { if (!picker) { popup = memnew(PopupPanel); + popup->set_wrap_controls(true); picker = memnew(ColorPicker); + picker->set_anchors_and_margins_preset(PRESET_WIDE); popup->add_child(picker); add_child(popup); picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed)); popup->connect("modal_closed", callable_mp(this, &ColorPickerButton::_modal_closed)); - popup->connect("about_to_show", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); + popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 1a231e368b..14bca0e2c8 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -38,7 +38,7 @@ #include "scene/gui/label.h" #include "scene/gui/panel.h" #include "scene/main/canvas_layer.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" #include "servers/visual_server.h" @@ -260,22 +260,22 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { } else { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); - add_icon_override(dname, p_value); + add_theme_icon_override(dname, p_value); } else if (name.begins_with("custom_shaders/")) { String dname = name.get_slicec('/', 1); - add_shader_override(dname, p_value); + add_theme_shader_override(dname, p_value); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); - add_style_override(dname, p_value); + add_theme_style_override(dname, p_value); } else if (name.begins_with("custom_fonts/")) { String dname = name.get_slicec('/', 1); - add_font_override(dname, p_value); + add_theme_font_override(dname, p_value); } else if (name.begins_with("custom_colors/")) { String dname = name.get_slicec('/', 1); - add_color_override(dname, p_value); + add_theme_color_override(dname, p_value); } else if (name.begins_with("custom_constants/")) { String dname = name.get_slicec('/', 1); - add_constant_override(dname, p_value); + add_theme_constant_override(dname, p_value); } else return false; } @@ -438,22 +438,30 @@ void Control::_resize(const Size2 &p_size) { void Control::add_child_notify(Node *p_child) { Control *child_c = Object::cast_to<Control>(p_child); - if (!child_c) - return; - if (child_c->data.theme.is_null() && data.theme_owner) { - _propagate_theme_changed(child_c, data.theme_owner); //need to propagate here, since many controls may require setting up stuff + 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); - if (!child_c) - return; - if (child_c->data.theme_owner && child_c->data.theme.is_null()) { - _propagate_theme_changed(child_c, NULL); + 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, NULL, NULL); + } + + Window *child_w = Object::cast_to<Window>(p_child); + + if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { + _propagate_theme_changed(child_w, NULL, NULL); } } @@ -486,76 +494,54 @@ void Control::_notification(int p_notification) { data.parent = Object::cast_to<Control>(get_parent()); - if (is_set_as_toplevel()) { - data.SI = get_viewport()->_gui_add_subwindow_control(this); - - if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { - data.theme_owner = data.parent->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); - } - - } else { - - Node *parent = this; //meh - Control *parent_control = NULL; - bool subwindow = false; + Node *parent = this; //meh + Control *parent_control = NULL; + bool subwindow = false; - while (parent) { - - parent = parent->get_parent(); - - if (!parent) - break; - - CanvasItem *ci = Object::cast_to<CanvasItem>(parent); - if (ci && ci->is_set_as_toplevel()) { - subwindow = true; - break; - } + while (parent) { - parent_control = Object::cast_to<Control>(parent); + parent = parent->get_parent(); - if (parent_control) { - break; - } else if (ci) { + if (!parent) + break; - } else { - break; - } + CanvasItem *ci = Object::cast_to<CanvasItem>(parent); + if (ci && ci->is_set_as_toplevel()) { + subwindow = true; + break; } - if (parent_control) { - //do nothing, has a parent control - if (data.theme.is_null() && parent_control->data.theme_owner) { - data.theme_owner = parent_control->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); - } - } else if (subwindow) { - //is a subwindow (process input before other controls for that canvas) - data.SI = get_viewport()->_gui_add_subwindow_control(this); - } else { - //is a regular root control - data.RI = get_viewport()->_gui_add_root_control(this); - } + parent_control = Object::cast_to<Control>(parent); - data.parent_canvas_item = get_parent_item(); - - if (data.parent_canvas_item) { + if (parent_control) { + break; + } else if (ci) { - data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed)); } else { - //connect viewport - get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed)); + break; } } - /* - if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { - data.theme_owner=data.parent->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); + if (parent_control && !subwindow) { + //do nothing, has a parent control and not toplevel + if (data.theme.is_null() && parent_control->data.theme_owner) { + data.theme_owner = parent_control->data.theme_owner; + notification(NOTIFICATION_THEME_CHANGED); + } + } else { + //is a regular root control or toplevel + data.RI = get_viewport()->_gui_add_root_control(this); } - */ + data.parent_canvas_item = get_parent_item(); + + if (data.parent_canvas_item) { + + data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed)); + } else { + //connect viewport + get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed)); + } } break; case NOTIFICATION_EXIT_CANVAS: { @@ -568,16 +554,6 @@ void Control::_notification(int p_notification) { get_viewport()->disconnect("size_changed", callable_mp(this, &Control::_size_changed)); } - if (data.MI) { - get_viewport()->_gui_remove_modal_control(data.MI); - data.MI = NULL; - } - - if (data.SI) { - get_viewport()->_gui_remove_subwindow_control(data.SI); - data.SI = NULL; - } - if (data.RI) { get_viewport()->_gui_remove_root_control(data.RI); data.RI = NULL; @@ -600,9 +576,6 @@ void Control::_notification(int p_notification) { data.parent->update(); update(); - if (data.SI) { - get_viewport()->_gui_set_subwindow_order_dirty(); - } if (data.RI) { get_viewport()->_gui_set_root_order_dirty(); } @@ -644,10 +617,6 @@ void Control::_notification(int p_notification) { minimum_size_changed(); update(); } break; - case NOTIFICATION_MODAL_CLOSE: { - - emit_signal("modal_closed"); - } break; case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { @@ -655,23 +624,14 @@ void Control::_notification(int p_notification) { if (get_viewport() != NULL) get_viewport()->_gui_hid_control(this); - if (is_inside_tree()) { - _modal_stack_remove(); - } - //remove key focus - //remove modalness + } else { data.minimum_size_valid = false; _size_changed(); } } break; - case SceneTree::NOTIFICATION_WM_UNFOCUS_REQUEST: { - - get_viewport()->_gui_unfocus_control(this); - - } break; } } @@ -787,19 +747,6 @@ void Control::set_drag_preview(Control *p_control) { get_viewport()->_gui_set_drag_preview(this, p_control); } -bool Control::is_window_modal_on_top() const { - - if (!is_inside_tree()) - return false; - - return get_viewport()->_gui_is_modal_on_top(this); -} - -uint64_t Control::get_modal_frame() const { - - return data.modal_frame; -} - Size2 Control::get_minimum_size() const { ScriptInstance *si = const_cast<Control *>(this)->get_script_instance(); @@ -813,50 +760,130 @@ Size2 Control::get_minimum_size() const { return Size2(); } -Ref<Texture2D> Control::get_icon(const StringName &p_name, const StringName &p_type) const { +template <class T> +bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &r_ret, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) { - if (p_type == StringName() || p_type == get_class_name()) { + // try with custom themes + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; - const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); - if (tex) - return *tex; + while (theme_owner || theme_owner_window) { + + StringName class_name = p_type; + + while (class_name != StringName()) { + if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) { + r_ret = (theme_owner->data.theme.operator->()->*get_func)(p_name, class_name); + return true; + } + + if (theme_owner_window && (theme_owner_window->theme.operator->()->*has_func)(p_name, class_name)) { + r_ret = (theme_owner_window->theme.operator->()->*get_func)(p_name, class_name); + return true; + } + + class_name = ClassDB::get_parent_class_nocheck(class_name); + } + + 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 = NULL; + theme_owner_window = NULL; + } + } } + return false; +} - StringName type = p_type ? p_type : get_class_name(); +bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) { // try with custom themes - Control *theme_owner = data.theme_owner; + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; - while (theme_owner) { + while (theme_owner || theme_owner_window) { - StringName class_name = type; + StringName class_name = p_type; while (class_name != StringName()) { - if (theme_owner->data.theme->has_icon(p_name, class_name)) { - return theme_owner->data.theme->get_icon(p_name, class_name); + if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) { + return true; + } + + if (theme_owner_window && (theme_owner_window->theme.operator->()->*has_func)(p_name, class_name)) { + return true; } class_name = ClassDB::get_parent_class_nocheck(class_name); } - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + 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 = NULL; + theme_owner_window = NULL; + } + } + } + return false; +} + +Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_type) const { + + if (p_type == StringName() || p_type == get_class_name()) { + + const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); + if (tex) + return *tex; + } + + StringName type = p_type ? p_type : get_class_name(); - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + return get_icons(data.theme_owner, data.theme_owner_window, p_name, type); +} + +Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { + + Ref<Texture2D> icon; + + if (_find_theme_item(p_theme_owner, p_theme_owner_window, icon, &Theme::get_icon, &Theme::has_icon, p_name, p_type)) { + return icon; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_icon(p_name, type)) { - return Theme::get_project_default()->get_icon(p_name, type); + if (Theme::get_project_default()->has_icon(p_name, p_type)) { + return Theme::get_project_default()->get_icon(p_name, p_type); } } - return Theme::get_default()->get_icon(p_name, type); + return Theme::get_default()->get_icon(p_name, p_type); } -Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_type) const { +Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_type) const { + if (p_type == StringName() || p_type == get_class_name()) { const Ref<Shader> *sdr = data.shader_override.getptr(p_name); @@ -866,39 +893,27 @@ Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_ty StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_shader(p_name, class_name)) { - return theme_owner->data.theme->get_shader(p_name, class_name); - } + return get_shaders(data.theme_owner, data.theme_owner_window, p_name, type); +} - class_name = ClassDB::get_parent_class_nocheck(class_name); - } +Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + Ref<Shader> shader; - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_type)) { + return shader; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, type)) { - return Theme::get_project_default()->get_shader(p_name, type); + if (Theme::get_project_default()->has_shader(p_name, p_type)) { + return Theme::get_project_default()->get_shader(p_name, p_type); } } - return Theme::get_default()->get_shader(p_name, type); + return Theme::get_default()->get_shader(p_name, p_type); } -Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &p_type) const { +Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { const Ref<StyleBox> *style = data.style_override.getptr(p_name); @@ -908,43 +923,27 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName & StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; + return get_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type); +} - StringName class_name = type; +Ref<StyleBox> Control::get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - while (theme_owner) { + Ref<StyleBox> stylebox; - while (class_name != StringName()) { - if (theme_owner->data.theme->has_stylebox(p_name, class_name)) { - return theme_owner->data.theme->get_stylebox(p_name, class_name); - } + if (_find_theme_item(p_theme_owner, p_theme_owner_window, stylebox, &Theme::get_stylebox, &Theme::has_stylebox, p_name, p_type)) { + return stylebox; + } - class_name = ClassDB::get_parent_class_nocheck(class_name); + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_stylebox(p_name, p_type)) { + return Theme::get_project_default()->get_stylebox(p_name, p_type); } - - class_name = type; - - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); - - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; } - while (class_name != StringName()) { - if (Theme::get_project_default().is_valid() && Theme::get_project_default()->has_stylebox(p_name, type)) - return Theme::get_project_default()->get_stylebox(p_name, type); - - if (Theme::get_default()->has_stylebox(p_name, class_name)) - return Theme::get_default()->get_stylebox(p_name, class_name); - - class_name = ClassDB::get_parent_class_nocheck(class_name); - } - return Theme::get_default()->get_stylebox(p_name, type); + return Theme::get_default()->get_stylebox(p_name, p_type); } -Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) const { + +Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { const Ref<Font> *font = data.font_override.getptr(p_name); @@ -954,34 +953,27 @@ Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; + return get_fonts(data.theme_owner, data.theme_owner_window, p_name, type); +} - while (theme_owner) { +Ref<Font> Control::get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - StringName class_name = type; + Ref<Font> font; - while (class_name != StringName()) { - if (theme_owner->data.theme->has_font(p_name, class_name)) { - return theme_owner->data.theme->get_font(p_name, class_name); - } + if (_find_theme_item(p_theme_owner, p_theme_owner_window, font, &Theme::get_font, &Theme::has_font, p_name, p_type)) { + return font; + } - class_name = ClassDB::get_parent_class_nocheck(class_name); + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_font(p_name, p_type)) { + return Theme::get_project_default()->get_font(p_name, p_type); } - - if (theme_owner->data.theme->get_default_theme_font().is_valid()) - return theme_owner->data.theme->get_default_theme_font(); - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); - - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; } - return Theme::get_default()->get_font(p_name, type); + return Theme::get_default()->get_font(p_name, p_type); } -Color Control::get_color(const StringName &p_name, const StringName &p_type) const { + +Color Control::get_theme_color(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { const Color *color = data.color_override.getptr(p_name); @@ -990,38 +982,27 @@ Color Control::get_color(const StringName &p_name, const StringName &p_type) con } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - StringName class_name = type; + return get_colors(data.theme_owner, data.theme_owner_window, p_name, type); +} - while (class_name != StringName()) { - if (theme_owner->data.theme->has_color(p_name, class_name)) { - return theme_owner->data.theme->get_color(p_name, class_name); - } +Color Control::get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - class_name = ClassDB::get_parent_class_nocheck(class_name); - } + Color color; - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); - - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_find_theme_item(p_theme_owner, p_theme_owner_window, color, &Theme::get_color, &Theme::has_color, p_name, p_type)) { + return color; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, type)) { - return Theme::get_project_default()->get_color(p_name, type); + if (Theme::get_project_default()->has_color(p_name, p_type)) { + return Theme::get_project_default()->get_color(p_name, p_type); } } - return Theme::get_default()->get_color(p_name, type); + return Theme::get_default()->get_color(p_name, p_type); } -int Control::get_constant(const StringName &p_name, const StringName &p_type) const { +int Control::get_theme_constant(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { const int *constant = data.constant_override.getptr(p_name); @@ -1030,303 +1011,213 @@ int Control::get_constant(const StringName &p_name, const StringName &p_type) co } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - while (class_name != StringName()) { - if (theme_owner->data.theme->has_constant(p_name, class_name)) { - return theme_owner->data.theme->get_constant(p_name, class_name); - } + return get_constants(data.theme_owner, data.theme_owner_window, p_name, type); +} - class_name = ClassDB::get_parent_class_nocheck(class_name); - } +int Control::get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + int constant; - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_find_theme_item(p_theme_owner, p_theme_owner_window, constant, &Theme::get_constant, &Theme::has_constant, p_name, p_type)) { + return constant; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_constant(p_name, type)) { - return Theme::get_project_default()->get_constant(p_name, type); + if (Theme::get_project_default()->has_constant(p_name, p_type)) { + return Theme::get_project_default()->get_constant(p_name, p_type); } } - return Theme::get_default()->get_constant(p_name, type); + return Theme::get_default()->get_constant(p_name, p_type); } -bool Control::has_icon_override(const StringName &p_name) const { +bool Control::has_theme_icon_override(const StringName &p_name) const { const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); return tex != NULL; } -bool Control::has_shader_override(const StringName &p_name) const { +bool Control::has_theme_shader_override(const StringName &p_name) const { const Ref<Shader> *sdr = data.shader_override.getptr(p_name); return sdr != NULL; } -bool Control::has_stylebox_override(const StringName &p_name) const { +bool Control::has_theme_stylebox_override(const StringName &p_name) const { const Ref<StyleBox> *style = data.style_override.getptr(p_name); return style != NULL; } -bool Control::has_font_override(const StringName &p_name) const { +bool Control::has_theme_font_override(const StringName &p_name) const { const Ref<Font> *font = data.font_override.getptr(p_name); return font != NULL; } -bool Control::has_color_override(const StringName &p_name) const { +bool Control::has_theme_color_override(const StringName &p_name) const { const Color *color = data.color_override.getptr(p_name); return color != NULL; } -bool Control::has_constant_override(const StringName &p_name) const { +bool Control::has_theme_constant_override(const StringName &p_name) const { const int *constant = data.constant_override.getptr(p_name); return constant != NULL; } -bool Control::has_icon(const StringName &p_name, const StringName &p_type) const { +bool Control::has_theme_icon(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_icon_override(p_name)) + if (has_theme_icon_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_icon(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } + return has_icons(data.theme_owner, data.theme_owner_window, p_name, type); +} - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); +bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_icon, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, type)) { + if (Theme::get_project_default()->has_color(p_name, p_type)) { return true; } } - return Theme::get_default()->has_icon(p_name, type); + return Theme::get_default()->has_icon(p_name, p_type); } -bool Control::has_shader(const StringName &p_name, const StringName &p_type) const { +bool Control::has_theme_shader(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_shader_override(p_name)) + if (has_theme_shader_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_shader(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } - - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + return has_shaders(data.theme_owner, data.theme_owner_window, p_name, type); +} +bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, type)) { + if (Theme::get_project_default()->has_shader(p_name, p_type)) { return true; } } - return Theme::get_default()->has_shader(p_name, type); + return Theme::get_default()->has_shader(p_name, p_type); } -bool Control::has_stylebox(const StringName &p_name, const StringName &p_type) const { + +bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_stylebox_override(p_name)) + if (has_theme_stylebox_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_stylebox(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } + return has_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type); +} - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); +bool Control::has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_stylebox, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_stylebox(p_name, type)) { + if (Theme::get_project_default()->has_stylebox(p_name, p_type)) { return true; } } - return Theme::get_default()->has_stylebox(p_name, type); + return Theme::get_default()->has_stylebox(p_name, p_type); } -bool Control::has_font(const StringName &p_name, const StringName &p_type) const { + +bool Control::has_theme_font(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_font_override(p_name)) + if (has_theme_font_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_font(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } - - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + return has_fonts(data.theme_owner, data.theme_owner_window, p_name, type); +} +bool Control::has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_font(p_name, type)) { + if (Theme::get_project_default()->has_font(p_name, p_type)) { return true; } } - return Theme::get_default()->has_font(p_name, type); + return Theme::get_default()->has_font(p_name, p_type); } -bool Control::has_color(const StringName &p_name, const StringName &p_type) const { +bool Control::has_theme_color(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_color_override(p_name)) + if (has_theme_color_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_color(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } - - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); + return has_colors(data.theme_owner, data.theme_owner_window, p_name, type); +} +bool Control::has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_color, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, type)) { + if (Theme::get_project_default()->has_color(p_name, p_type)) { return true; } } - return Theme::get_default()->has_color(p_name, type); + return Theme::get_default()->has_color(p_name, p_type); } -bool Control::has_constant(const StringName &p_name, const StringName &p_type) const { +bool Control::has_theme_constant(const StringName &p_name, const StringName &p_type) const { if (p_type == StringName() || p_type == get_class_name()) { - if (has_constant_override(p_name)) + if (has_theme_constant_override(p_name)) return true; } StringName type = p_type ? p_type : get_class_name(); - // try with custom themes - Control *theme_owner = data.theme_owner; - - while (theme_owner) { - - StringName class_name = type; - - while (class_name != StringName()) { - if (theme_owner->data.theme->has_constant(p_name, class_name)) { - return true; - } - class_name = ClassDB::get_parent_class_nocheck(class_name); - } + return has_constants(data.theme_owner, data.theme_owner_window, p_name, p_type); +} - Control *parent = Object::cast_to<Control>(theme_owner->get_parent()); +bool Control::has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (parent) - theme_owner = parent->data.theme_owner; - else - theme_owner = NULL; + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_constant, p_name, p_type)) { + return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_constant(p_name, type)) { + if (Theme::get_project_default()->has_constant(p_name, p_type)) { return true; } } - return Theme::get_default()->has_constant(p_name, type); + return Theme::get_default()->has_constant(p_name, p_type); } Rect2 Control::get_parent_anchorable_rect() const { @@ -1769,6 +1660,17 @@ Point2 Control::get_global_position() const { return get_global_transform().get_origin(); } +Point2 Control::get_screen_position() const { + ERR_FAIL_COND_V(!is_inside_tree(), Point2()); + Point2 global_pos = get_global_position(); + Window *w = Object::cast_to<Window>(get_viewport()); + if (w && !w->is_embedding_subwindows()) { + global_pos += w->get_position(); + } + + return global_pos; +} + void Control::_set_global_position(const Point2 &p_point) { set_global_position(p_point); } @@ -1863,6 +1765,20 @@ Rect2 Control::get_global_rect() const { return Rect2(get_global_position(), get_size()); } +Rect2 Control::get_screen_rect() const { + + ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); + + Rect2 r(get_global_position(), get_size()); + + Window *w = Object::cast_to<Window>(get_viewport()); + if (w && !w->is_embedding_subwindows()) { + r.position += w->get_position(); + } + + return r; +} + Rect2 Control::get_window_rect() const { ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); Rect2 gr = get_global_rect(); @@ -1880,7 +1796,7 @@ Rect2 Control::get_anchorable_rect() const { return Rect2(Point2(), get_size()); } -void Control::add_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) { +void Control::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) { if (data.icon_override.has(p_name)) { data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); @@ -1898,7 +1814,7 @@ void Control::add_icon_override(const StringName &p_name, const Ref<Texture2D> & notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) { +void Control::add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) { if (data.shader_override.has(p_name)) { data.shader_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); @@ -1915,7 +1831,7 @@ void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p } notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { +void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { if (data.style_override.has(p_name)) { data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); @@ -1933,7 +1849,7 @@ void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> & notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_font) { +void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) { if (data.font_override.has(p_name)) { data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); @@ -1950,12 +1866,12 @@ void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_fon } notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_color_override(const StringName &p_name, const Color &p_color) { +void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) { data.color_override[p_name] = p_color; notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_constant_override(const StringName &p_name, int p_constant) { +void Control::add_theme_constant_override(const StringName &p_name, int p_constant) { data.constant_override[p_name] = p_constant; notification(NOTIFICATION_THEME_CHANGED); @@ -2049,7 +1965,7 @@ Control *Control::find_next_valid_focus() const { next_child = const_cast<Control *>(this); while (next_child) { - if (next_child->data.SI || next_child->data.RI) + if (next_child->data.RI) break; next_child = next_child->get_parent_control(); } @@ -2192,53 +2108,29 @@ bool Control::is_toplevel_control() const { return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel()); } -void Control::show_modal(bool p_exclusive) { - - ERR_FAIL_COND(!is_inside_tree()); - ERR_FAIL_COND(!data.SI); - - if (is_visible_in_tree()) - hide(); - - ERR_FAIL_COND(data.MI != NULL); - show(); - raise(); - data.modal_exclusive = p_exclusive; - data.MI = get_viewport()->_gui_show_modal(this); - data.modal_frame = Engine::get_singleton()->get_frames_drawn(); -} +void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) { -void Control::_modal_set_prev_focus_owner(ObjectID p_prev) { - data.modal_prev_focus_owner = p_prev; -} - -void Control::_modal_stack_remove() { - - ERR_FAIL_COND(!is_inside_tree()); + Control *c = Object::cast_to<Control>(p_at); - if (!data.MI) + if (c && c != p_owner && c->data.theme.is_valid()) // has a theme, this can't be propagated return; - List<Control *>::Element *element = data.MI; - data.MI = NULL; - - get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner); - - data.modal_prev_focus_owner = ObjectID(); -} + Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr; -void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, 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 + if (w && w != p_owner_window && w->theme.is_valid()) // has a theme, this can't be propagated return; 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_assign); + _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); + } } } @@ -2246,14 +2138,26 @@ void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool 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); + } + + if (w) { + + if (p_assign) { + w->theme_owner = p_owner; + w->theme_owner_window = p_owner_window; } - c->notification(NOTIFICATION_THEME_CHANGED); + w->notification(Window::NOTIFICATION_THEME_CHANGED); + w->emit_signal(SceneStringNames::get_singleton()->theme_changed); } } void Control::_theme_changed() { - _propagate_theme_changed(this, this, false); + _propagate_theme_changed(this, this, nullptr, false); } void Control::set_theme(const Ref<Theme> &p_theme) { @@ -2269,15 +2173,21 @@ void Control::set_theme(const Ref<Theme> &p_theme) { if (!p_theme.is_null()) { data.theme_owner = this; - _propagate_theme_changed(this, this); + data.theme_owner_window = nullptr; + _propagate_theme_changed(this, this, nullptr); } else { - Control *parent = cast_to<Control>(get_parent()); - if (parent && parent->data.theme_owner) { - _propagate_theme_changed(this, parent->data.theme_owner); - } else { + Control *parent_c = Object::cast_to<Control>(get_parent()); - _propagate_theme_changed(this, NULL); + 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); + } } } @@ -2440,8 +2350,6 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) { Control *c = Object::cast_to<Control>(base); if (c) { - if (c->data.SI) - break; if (c->data.RI) break; } @@ -2511,7 +2419,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con Node *child = p_at->get_child(i); Control *childc = Object::cast_to<Control>(child); - if (childc && childc->data.SI) + if (childc && childc->data.RI) continue; //subwindow, ignore _window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest); } @@ -2569,6 +2477,12 @@ void Control::minimum_size_changed() { invalidate->data.minimum_size_valid = false; if (invalidate->is_set_as_toplevel()) break; // do not go further up + if (!invalidate->data.parent && get_parent()) { + Window *parent_window = Object::cast_to<Window>(get_parent()); + if (parent_window && parent_window->is_wrapping_controls()) { + parent_window->child_controls_changed(); + } + } invalidate = invalidate->data.parent; } @@ -2599,16 +2513,6 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } -void Control::set_pass_on_modal_close_click(bool p_pass_on) { - - data.pass_on_modal_close_click = p_pass_on; -} - -bool Control::pass_on_modal_close_click() const { - - return data.pass_on_modal_close_click; -} - Control *Control::get_focus_owner() const { ERR_FAIL_COND_V(!is_inside_tree(), NULL); @@ -2658,6 +2562,7 @@ float Control::get_rotation_degrees() const { void Control::_override_changed() { notification(NOTIFICATION_THEME_CHANGED); + emit_signal(SceneStringNames::get_singleton()->theme_changed); minimum_size_changed(); // overrides are likely to affect minimum size } @@ -2701,7 +2606,7 @@ Control *Control::get_root_parent_control() const { if (c) { root = c; - if (c->data.RI || c->data.MI || c->is_toplevel_control()) + if (c->data.RI || c->is_toplevel_control()) break; } @@ -2853,7 +2758,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position); ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect); ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect); - ClassDB::bind_method(D_METHOD("show_modal", "exclusive"), &Control::show_modal, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_focus_mode", "mode"), &Control::set_focus_mode); ClassDB::bind_method(D_METHOD("get_focus_mode"), &Control::get_focus_mode); ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus); @@ -2873,31 +2777,31 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Control::set_theme); ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme); - ClassDB::bind_method(D_METHOD("add_icon_override", "name", "texture"), &Control::add_icon_override); - ClassDB::bind_method(D_METHOD("add_shader_override", "name", "shader"), &Control::add_shader_override); - ClassDB::bind_method(D_METHOD("add_stylebox_override", "name", "stylebox"), &Control::add_style_override); - ClassDB::bind_method(D_METHOD("add_font_override", "name", "font"), &Control::add_font_override); - ClassDB::bind_method(D_METHOD("add_color_override", "name", "color"), &Control::add_color_override); - ClassDB::bind_method(D_METHOD("add_constant_override", "name", "constant"), &Control::add_constant_override); - - ClassDB::bind_method(D_METHOD("get_icon", "name", "type"), &Control::get_icon, DEFVAL("")); - ClassDB::bind_method(D_METHOD("get_stylebox", "name", "type"), &Control::get_stylebox, DEFVAL("")); - ClassDB::bind_method(D_METHOD("get_font", "name", "type"), &Control::get_font, DEFVAL("")); - ClassDB::bind_method(D_METHOD("get_color", "name", "type"), &Control::get_color, DEFVAL("")); - ClassDB::bind_method(D_METHOD("get_constant", "name", "type"), &Control::get_constant, DEFVAL("")); - - ClassDB::bind_method(D_METHOD("has_icon_override", "name"), &Control::has_icon_override); - ClassDB::bind_method(D_METHOD("has_shader_override", "name"), &Control::has_shader_override); - ClassDB::bind_method(D_METHOD("has_stylebox_override", "name"), &Control::has_stylebox_override); - ClassDB::bind_method(D_METHOD("has_font_override", "name"), &Control::has_font_override); - ClassDB::bind_method(D_METHOD("has_color_override", "name"), &Control::has_color_override); - ClassDB::bind_method(D_METHOD("has_constant_override", "name"), &Control::has_constant_override); - - ClassDB::bind_method(D_METHOD("has_icon", "name", "type"), &Control::has_icon, DEFVAL("")); - ClassDB::bind_method(D_METHOD("has_stylebox", "name", "type"), &Control::has_stylebox, DEFVAL("")); - ClassDB::bind_method(D_METHOD("has_font", "name", "type"), &Control::has_font, DEFVAL("")); - ClassDB::bind_method(D_METHOD("has_color", "name", "type"), &Control::has_color, DEFVAL("")); - ClassDB::bind_method(D_METHOD("has_constant", "name", "type"), &Control::has_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_override); + ClassDB::bind_method(D_METHOD("add_theme_shader_override", "name", "shader"), &Control::add_theme_shader_override); + ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Control::add_theme_style_override); + ClassDB::bind_method(D_METHOD("add_theme_font_override", "name", "font"), &Control::add_theme_font_override); + ClassDB::bind_method(D_METHOD("add_theme_color_override", "name", "color"), &Control::add_theme_color_override); + ClassDB::bind_method(D_METHOD("add_theme_constant_override", "name", "constant"), &Control::add_theme_constant_override); + + ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "type"), &Control::get_theme_icon, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Control::get_theme_stylebox, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Control::get_theme_font, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Control::get_theme_color, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Control::get_theme_constant, DEFVAL("")); + + ClassDB::bind_method(D_METHOD("has_theme_icon_override", "name"), &Control::has_theme_icon_override); + ClassDB::bind_method(D_METHOD("has_theme_shader_override", "name"), &Control::has_theme_shader_override); + ClassDB::bind_method(D_METHOD("has_theme_stylebox_override", "name"), &Control::has_theme_stylebox_override); + ClassDB::bind_method(D_METHOD("has_theme_font_override", "name"), &Control::has_theme_font_override); + ClassDB::bind_method(D_METHOD("has_theme_color_override", "name"), &Control::has_theme_color_override); + ClassDB::bind_method(D_METHOD("has_theme_constant_override", "name"), &Control::has_theme_constant_override); + + ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Control::has_theme_icon, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Control::has_theme_stylebox, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Control::has_theme_font, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Control::has_theme_color, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Control::has_theme_constant, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control); @@ -3013,7 +2917,6 @@ void Control::_bind_methods() { BIND_CONSTANT(NOTIFICATION_FOCUS_ENTER); BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT); BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); - BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE); BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN); BIND_CONSTANT(NOTIFICATION_SCROLL_END); @@ -3082,7 +2985,7 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("focus_exited")); ADD_SIGNAL(MethodInfo("size_flags_changed")); ADD_SIGNAL(MethodInfo("minimum_size_changed")); - ADD_SIGNAL(MethodInfo("modal_closed")); + ADD_SIGNAL(MethodInfo("theme_changed")); BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point"))); } @@ -3091,13 +2994,10 @@ Control::Control() { data.parent = NULL; data.mouse_filter = MOUSE_FILTER_STOP; - data.pass_on_modal_close_click = true; - data.SI = NULL; - data.MI = NULL; data.RI = NULL; data.theme_owner = NULL; - data.modal_exclusive = false; + data.theme_owner_window = NULL; data.default_cursor = CURSOR_ARROW; data.h_size_flags = SIZE_FILL; data.v_size_flags = SIZE_FILL; @@ -3106,7 +3006,6 @@ Control::Control() { data.parent_canvas_item = NULL; data.scale = Vector2(1, 1); - data.modal_frame = 0; data.block_minimum_size_adjust = false; data.disable_visibility_clip = false; data.h_grow = GROW_DIRECTION_END; diff --git a/scene/gui/control.h b/scene/gui/control.h index 15a32b8f67..c52e80fa70 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -168,8 +168,6 @@ private: float expand; Point2 custom_minimum_size; - bool pass_on_modal_close_click; - MouseFilter mouse_filter; bool clip_contents; @@ -179,21 +177,16 @@ private: Control *parent; ObjectID drag_owner; - bool modal_exclusive; - uint64_t modal_frame; //frame used to put something as modal Ref<Theme> theme; Control *theme_owner; + Window *theme_owner_window; String tooltip; CursorShape default_cursor; - List<Control *>::Element *MI; //modal item - List<Control *>::Element *SI; List<Control *>::Element *RI; CanvasItem *parent_canvas_item; - ObjectID modal_prev_focus_owner; - NodePath focus_neighbour[4]; NodePath focus_next; NodePath focus_prev; @@ -218,7 +211,6 @@ private: void _set_global_position(const Point2 &p_point); void _set_size(const Size2 &p_size); - void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true); void _theme_changed(); void _change_notify_margins(); @@ -240,10 +232,29 @@ private: Transform2D _get_internal_transform() const; friend class Viewport; - void _modal_stack_remove(); - void _modal_set_prev_focus_owner(ObjectID p_prev); void _update_minimum_size_cache(); + friend class Window; + static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true); + + template <class T> + _FORCE_INLINE_ static bool _find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type); + + _FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type); + + static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static Color get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + + static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); protected: virtual void add_child_notify(Node *p_child); @@ -272,7 +283,6 @@ public: NOTIFICATION_FOCUS_ENTER = 43, NOTIFICATION_FOCUS_EXIT = 44, NOTIFICATION_THEME_CHANGED = 45, - NOTIFICATION_MODAL_CLOSE = 46, NOTIFICATION_SCROLL_BEGIN = 47, NOTIFICATION_SCROLL_END = 48, @@ -320,9 +330,6 @@ public: void set_custom_minimum_size(const Size2 &p_custom); Size2 get_custom_minimum_size() const; - bool is_window_modal_on_top() const; - uint64_t get_modal_frame() const; //frame in which this was made modal - Control *get_parent_control() const; /* POSITIONING */ @@ -349,12 +356,14 @@ public: void set_global_position(const Point2 &p_point, bool p_keep_margins = false); Point2 get_position() const; Point2 get_global_position() const; + Point2 get_screen_position() const; void set_size(const Size2 &p_size, bool p_keep_margins = false); Size2 get_size() const; Rect2 get_rect() const; Rect2 get_global_rect() const; + Rect2 get_screen_rect() const; Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server Rect2 get_anchorable_rect() const; @@ -375,8 +384,6 @@ public: void set_scale(const Vector2 &p_scale); Vector2 get_scale() const; - void show_modal(bool p_exclusive = false); - void set_theme(const Ref<Theme> &p_theme); Ref<Theme> get_theme() const; @@ -415,38 +422,35 @@ public: void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; - void set_pass_on_modal_close_click(bool p_pass_on); - bool pass_on_modal_close_click() const; - /* SKINNING */ - void add_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon); - void add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader); - void add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style); - void add_font_override(const StringName &p_name, const Ref<Font> &p_font); - void add_color_override(const StringName &p_name, const Color &p_color); - void add_constant_override(const StringName &p_name, int p_constant); - - Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<Shader> get_shader(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<Font> get_font(const StringName &p_name, const StringName &p_type = StringName()) const; - Color get_color(const StringName &p_name, const StringName &p_type = StringName()) const; - int get_constant(const StringName &p_name, const StringName &p_type = StringName()) const; - - bool has_icon_override(const StringName &p_name) const; - bool has_shader_override(const StringName &p_name) const; - bool has_stylebox_override(const StringName &p_name) const; - bool has_font_override(const StringName &p_name) const; - bool has_color_override(const StringName &p_name) const; - bool has_constant_override(const StringName &p_name) const; - - bool has_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_shader(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_font(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_color(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon); + void add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader); + void add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style); + void add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font); + void add_theme_color_override(const StringName &p_name, const Color &p_color); + void add_theme_constant_override(const StringName &p_name, int p_constant); + + Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; + Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; + int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + + bool has_theme_icon_override(const StringName &p_name) const; + bool has_theme_shader_override(const StringName &p_name) const; + bool has_theme_stylebox_override(const StringName &p_name) const; + bool has_theme_font_override(const StringName &p_name) const; + bool has_theme_color_override(const StringName &p_name) const; + bool has_theme_constant_override(const StringName &p_name) const; + + bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; /* TOOLTIP */ diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 6cadd0a63e..2e87a92969 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "dialogs.h" + +#include "core/os/keyboard.h" #include "core/print_string.h" #include "core/translation.h" #include "line_edit.h" @@ -36,362 +38,61 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" #include "editor/editor_scale.h" -#include "scene/main/viewport.h" // Only used to check for more modals when dimming the editor. +#include "scene/main/window.h" // Only used to check for more modals when dimming the editor. #endif -// WindowDialog - -void WindowDialog::_post_popup() { - - drag_type = DRAG_NONE; // just in case -} - -void WindowDialog::_fix_size() { - - // Perhaps this should be called when the viewport resizes as well or windows go out of bounds... - - // Ensure the whole window is visible. - Point2i pos = get_global_position(); - Size2i size = get_size(); - Size2i viewport_size = get_viewport_rect().size; - - // Windows require additional padding to keep the window chrome visible. - Ref<StyleBox> panel = get_stylebox("panel", "WindowDialog"); - float top = 0; - float left = 0; - float bottom = 0; - float right = 0; - // Check validity, because the theme could contain a different type of StyleBox. - if (panel->get_class() == "StyleBoxTexture") { - Ref<StyleBoxTexture> panel_texture = Object::cast_to<StyleBoxTexture>(*panel); - top = panel_texture->get_expand_margin_size(MARGIN_TOP); - left = panel_texture->get_expand_margin_size(MARGIN_LEFT); - bottom = panel_texture->get_expand_margin_size(MARGIN_BOTTOM); - right = panel_texture->get_expand_margin_size(MARGIN_RIGHT); - } else if (panel->get_class() == "StyleBoxFlat") { - Ref<StyleBoxFlat> panel_flat = Object::cast_to<StyleBoxFlat>(*panel); - top = panel_flat->get_expand_margin_size(MARGIN_TOP); - left = panel_flat->get_expand_margin_size(MARGIN_LEFT); - bottom = panel_flat->get_expand_margin_size(MARGIN_BOTTOM); - right = panel_flat->get_expand_margin_size(MARGIN_RIGHT); - } - - pos.x = MAX(left, MIN(pos.x, viewport_size.x - size.x - right)); - pos.y = MAX(top, MIN(pos.y, viewport_size.y - size.y - bottom)); - set_global_position(pos); +// AcceptDialog - if (resizable) { - size.x = MIN(size.x, viewport_size.x - left - right); - size.y = MIN(size.y, viewport_size.y - top - bottom); - set_size(size); +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) { + _cancel_pressed(); } } -bool WindowDialog::has_point(const Point2 &p_point) const { - - Rect2 r(Point2(), get_size()); - - // Enlarge upwards for title bar. - int title_height = get_constant("title_height", "WindowDialog"); - r.position.y -= title_height; - r.size.y += title_height; - - // Inflate by the resizable border thickness. - if (resizable) { - int scaleborder_size = get_constant("scaleborder_size", "WindowDialog"); - r.position.x -= scaleborder_size; - r.size.width += scaleborder_size * 2; - r.position.y -= scaleborder_size; - r.size.height += scaleborder_size * 2; - } - - return r.has_point(p_point); +void AcceptDialog::_parent_focused() { + _cancel_pressed(); } -void WindowDialog::_gui_input(const Ref<InputEvent> &p_event) { - - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { - - if (mb->is_pressed()) { - // Begin a possible dragging operation. - drag_type = _drag_hit_test(Point2(mb->get_position().x, mb->get_position().y)); - if (drag_type != DRAG_NONE) - drag_offset = get_global_mouse_position() - get_position(); - drag_offset_far = get_position() + get_size() - get_global_mouse_position(); - } else if (drag_type != DRAG_NONE && !mb->is_pressed()) { - // End a dragging operation. - drag_type = DRAG_NONE; - } - } +void AcceptDialog::_notification(int p_what) { - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - - if (drag_type == DRAG_NONE) { - // Update the cursor while moving along the borders. - CursorShape cursor = CURSOR_ARROW; - if (resizable) { - int preview_drag_type = _drag_hit_test(Point2(mm->get_position().x, mm->get_position().y)); - switch (preview_drag_type) { - case DRAG_RESIZE_TOP: - case DRAG_RESIZE_BOTTOM: - cursor = CURSOR_VSIZE; - break; - case DRAG_RESIZE_LEFT: - case DRAG_RESIZE_RIGHT: - cursor = CURSOR_HSIZE; - break; - case DRAG_RESIZE_TOP + DRAG_RESIZE_LEFT: - case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_RIGHT: - cursor = CURSOR_FDIAGSIZE; - break; - case DRAG_RESIZE_TOP + DRAG_RESIZE_RIGHT: - case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_LEFT: - cursor = CURSOR_BDIAGSIZE; - break; + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + + get_ok()->grab_focus(); + _update_child_rects(); + parent_visible = get_parent_visible_window(); + if (parent_visible) { + parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); } - } - if (get_cursor_shape() != cursor) - set_default_cursor_shape(cursor); - } else { - // Update while in a dragging operation. - Point2 global_pos = get_global_mouse_position(); - global_pos.y = MAX(global_pos.y, 0); // Ensure title bar stays visible. - - Rect2 rect = get_rect(); - Size2 min_size = get_combined_minimum_size(); - - if (drag_type == DRAG_MOVE) { - rect.position = global_pos - drag_offset; } else { - if (drag_type & DRAG_RESIZE_TOP) { - int bottom = rect.position.y + rect.size.height; - int max_y = bottom - min_size.height; - rect.position.y = MIN(global_pos.y - drag_offset.y, max_y); - rect.size.height = bottom - rect.position.y; - } else if (drag_type & DRAG_RESIZE_BOTTOM) { - rect.size.height = global_pos.y - rect.position.y + drag_offset_far.y; - } - if (drag_type & DRAG_RESIZE_LEFT) { - int right = rect.position.x + rect.size.width; - int max_x = right - min_size.width; - rect.position.x = MIN(global_pos.x - drag_offset.x, max_x); - rect.size.width = right - rect.position.x; - } else if (drag_type & DRAG_RESIZE_RIGHT) { - rect.size.width = global_pos.x - rect.position.x + drag_offset_far.x; + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible = nullptr; } } - set_size(rect.size); - set_position(rect.position); - } - } -} - -void WindowDialog::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_DRAW: { - RID canvas = get_canvas_item(); - - // Draw the background. - Ref<StyleBox> panel = get_stylebox("panel"); - Size2 size = get_size(); - panel->draw(canvas, Rect2(0, 0, size.x, size.y)); - - // Draw the title bar text. - Ref<Font> title_font = get_font("title_font", "WindowDialog"); - Color title_color = get_color("title_color", "WindowDialog"); - int title_height = get_constant("title_height", "WindowDialog"); - int font_height = title_font->get_height() - title_font->get_descent() * 2; - int x = (size.x - title_font->get_string_size(xl_title).x) / 2; - int y = (-title_height + font_height) / 2; - title_font->draw(canvas, Point2(x, y), xl_title, title_color, size.x - panel->get_minimum_size().x); } break; - case NOTIFICATION_THEME_CHANGED: - case NOTIFICATION_ENTER_TREE: { - close_button->set_normal_texture(get_icon("close", "WindowDialog")); - close_button->set_pressed_texture(get_icon("close", "WindowDialog")); - close_button->set_hover_texture(get_icon("close_highlight", "WindowDialog")); - close_button->set_anchor(MARGIN_LEFT, ANCHOR_END); - close_button->set_begin(Point2(-get_constant("close_h_ofs", "WindowDialog"), -get_constant("close_v_ofs", "WindowDialog"))); - } break; - - case NOTIFICATION_TRANSLATION_CHANGED: { - String new_title = tr(title); - if (new_title != xl_title) { - xl_title = new_title; - minimum_size_changed(); - update(); - } + case NOTIFICATION_THEME_CHANGED: { + bg->add_theme_style_override("panel", bg->get_theme_stylebox("panel", "AcceptDialog")); } break; - case NOTIFICATION_MOUSE_EXIT: { - // Reset the mouse cursor when leaving the resizable window border. - if (resizable && !drag_type) { - if (get_default_cursor_shape() != CURSOR_ARROW) - set_default_cursor_shape(CURSOR_ARROW); + case NOTIFICATION_EXIT_TREE: { + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible = nullptr; } } break; - -#ifdef TOOLS_ENABLED - case NOTIFICATION_POST_POPUP: { - if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) { - was_editor_dimmed = EditorNode::get_singleton()->is_editor_dimmed(); - EditorNode::get_singleton()->dim_editor(true); - } - } break; - - case NOTIFICATION_POPUP_HIDE: { - if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton() && !was_editor_dimmed) { - EditorNode::get_singleton()->dim_editor(false); - set_pass_on_modal_close_click(false); + case NOTIFICATION_READY: + case NOTIFICATION_WM_SIZE_CHANGED: { + if (is_visible()) { + _update_child_rects(); } } break; -#endif - } -} - -void WindowDialog::_closed() { - - _close_pressed(); - hide(); -} - -int WindowDialog::_drag_hit_test(const Point2 &pos) const { - int drag_type = DRAG_NONE; - - if (resizable) { - int title_height = get_constant("title_height", "WindowDialog"); - int scaleborder_size = get_constant("scaleborder_size", "WindowDialog"); - - Rect2 rect = get_rect(); - - if (pos.y < (-title_height + scaleborder_size)) - drag_type = DRAG_RESIZE_TOP; - else if (pos.y >= (rect.size.height - scaleborder_size)) - drag_type = DRAG_RESIZE_BOTTOM; - if (pos.x < scaleborder_size) - drag_type |= DRAG_RESIZE_LEFT; - else if (pos.x >= (rect.size.width - scaleborder_size)) - drag_type |= DRAG_RESIZE_RIGHT; - } - - if (drag_type == DRAG_NONE && pos.y < 0) - drag_type = DRAG_MOVE; - - return drag_type; -} - -void WindowDialog::set_title(const String &p_title) { - - if (title != p_title) { - title = p_title; - xl_title = tr(p_title); - minimum_size_changed(); - update(); - } -} -String WindowDialog::get_title() const { - - return title; -} - -void WindowDialog::set_resizable(bool p_resizable) { - resizable = p_resizable; -} -bool WindowDialog::get_resizable() const { - return resizable; -} - -Size2 WindowDialog::get_minimum_size() const { - - Ref<Font> font = get_font("title_font", "WindowDialog"); - - const int button_width = close_button->get_combined_minimum_size().x; - const int title_width = font->get_string_size(xl_title).x; - const int padding = button_width / 2; - const int button_area = button_width + padding; - - // As the title gets centered, title_width + close_button_width is not enough. - // We want a width w, such that w / 2 - title_width / 2 >= button_area, i.e. - // w >= 2 * button_area + title_width - - return Size2(2 * button_area + title_width, 1); -} - -TextureButton *WindowDialog::get_close_button() { - - return close_button; -} - -void WindowDialog::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_gui_input"), &WindowDialog::_gui_input); - ClassDB::bind_method(D_METHOD("set_title", "title"), &WindowDialog::set_title); - ClassDB::bind_method(D_METHOD("get_title"), &WindowDialog::get_title); - ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &WindowDialog::set_resizable); - ClassDB::bind_method(D_METHOD("get_resizable"), &WindowDialog::get_resizable); - ClassDB::bind_method(D_METHOD("get_close_button"), &WindowDialog::get_close_button); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "window_title", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_title", "get_title"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_resizable", "get_resizable"); -} - -WindowDialog::WindowDialog() { - - drag_type = DRAG_NONE; - resizable = false; - close_button = memnew(TextureButton); - add_child(close_button); - close_button->connect("pressed", callable_mp(this, &WindowDialog::_closed)); - -#ifdef TOOLS_ENABLED - was_editor_dimmed = false; -#endif -} - -WindowDialog::~WindowDialog() { -} - -// PopupDialog - -void PopupDialog::_notification(int p_what) { - - if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); - get_stylebox("panel")->draw(ci, Rect2(Point2(), get_size())); - } -} - -PopupDialog::PopupDialog() { -} - -PopupDialog::~PopupDialog() { -} - -// AcceptDialog - -void AcceptDialog::_post_popup() { - - WindowDialog::_post_popup(); - get_ok()->grab_focus(); -} - -void AcceptDialog::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_MODAL_CLOSE: { - cancel_pressed(); - } break; - - case NOTIFICATION_READY: - case NOTIFICATION_RESIZED: { - _update_child_rects(); + case NOTIFICATION_WM_CLOSE_REQUEST: { + _cancel_pressed(); } break; } } @@ -404,20 +105,28 @@ void AcceptDialog::_text_entered(const String &p_text) { void AcceptDialog::_ok_pressed() { if (hide_on_ok) - hide(); + set_visible(false); ok_pressed(); emit_signal("confirmed"); } -void AcceptDialog::_close_pressed() { +void AcceptDialog::_cancel_pressed() { + + Window *parent_window = parent_visible; + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible = nullptr; + } + + call_deferred("hide"); + + emit_signal("cancelled"); cancel_pressed(); -} -// FIXME: This is redundant with _closed_pressed, but there's a slight behavior -// change (WindowDialog's _closed() also calls hide()) which should be assessed. -void AcceptDialog::_on_close_pressed() { - _closed(); // From WindowDialog. + if (parent_window) { + //parent_window->grab_focus(); + } } String AcceptDialog::get_text() const { @@ -427,8 +136,10 @@ String AcceptDialog::get_text() const { void AcceptDialog::set_text(String p_text) { label->set_text(p_text); - minimum_size_changed(); - _update_child_rects(); + child_controls_changed(); + if (is_visible()) { + _update_child_rects(); + } } void AcceptDialog::set_hide_on_ok(bool p_hide) { @@ -463,7 +174,7 @@ void AcceptDialog::_update_child_rects() { if (label->get_text().empty()) { label_size.height = 0; } - int margin = get_constant("margin", "Dialogs"); + int margin = hbc->get_theme_constant("margin", "Dialogs"); Size2 size = get_size(); Size2 hminsize = hbc->get_combined_minimum_size(); @@ -475,7 +186,7 @@ void AcceptDialog::_update_child_rects() { if (!c) continue; - if (c == hbc || c == label || c == get_close_button() || c->is_set_as_toplevel()) + if (c == hbc || c == label || c == bg || c->is_set_as_toplevel()) continue; c->set_position(cpos); @@ -487,11 +198,14 @@ void AcceptDialog::_update_child_rects() { hbc->set_position(cpos); hbc->set_size(csize); + + bg->set_position(Point2()); + bg->set_size(size); } -Size2 AcceptDialog::get_minimum_size() const { +Size2 AcceptDialog::_get_contents_minimum_size() const { - int margin = get_constant("margin", "Dialogs"); + int margin = hbc->get_theme_constant("margin", "Dialogs"); Size2 minsize = label->get_combined_minimum_size(); for (int i = 0; i < get_child_count(); i++) { @@ -499,7 +213,7 @@ Size2 AcceptDialog::get_minimum_size() const { if (!c) continue; - if (c == hbc || c == label || c == const_cast<AcceptDialog *>(this)->get_close_button() || c->is_set_as_toplevel()) + if (c == hbc || c == label || c->is_set_as_toplevel()) continue; Size2 cminsize = c->get_combined_minimum_size(); @@ -513,7 +227,7 @@ Size2 AcceptDialog::get_minimum_size() const { minsize.x += margin * 2; minsize.y += margin * 3; //one as separation between hbc and child - Size2 wmsize = WindowDialog::get_minimum_size(); + Size2 wmsize = get_min_size(); minsize.x = MAX(wmsize.x, minsize.x); return minsize; } @@ -551,7 +265,7 @@ Button *AcceptDialog::add_cancel(const String &p_cancel) { if (p_cancel == "") c = RTR("Cancel"); Button *b = swap_ok_cancel ? add_button(c, true) : add_button(c); - b->connect("pressed", callable_mp(this, &AcceptDialog::_on_close_pressed)); + b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); return b; } @@ -570,6 +284,7 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("has_autowrap"), &AcceptDialog::has_autowrap); ADD_SIGNAL(MethodInfo("confirmed")); + ADD_SIGNAL(MethodInfo("cancelled")); ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING_NAME, "action"))); ADD_GROUP("Dialog", "dialog"); @@ -586,12 +301,23 @@ void AcceptDialog::set_swap_ok_cancel(bool p_swap) { AcceptDialog::AcceptDialog() { - int margin = get_constant("margin", "Dialogs"); - int button_margin = get_constant("button_margin", "Dialogs"); + parent_visible = nullptr; + + set_wrap_controls(true); + set_visible(false); + set_transient(true); + + bg = memnew(Panel); + add_child(bg); + + hbc = memnew(HBoxContainer); + + int margin = hbc->get_theme_constant("margin", "Dialogs"); + int button_margin = hbc->get_theme_constant("button_margin", "Dialogs"); label = memnew(Label); - label->set_anchor(MARGIN_RIGHT, ANCHOR_END); - label->set_anchor(MARGIN_BOTTOM, ANCHOR_END); + label->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END); + label->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END); label->set_begin(Point2(margin, margin)); label->set_end(Point2(-margin, -button_margin - 10)); add_child(label); @@ -606,10 +332,11 @@ AcceptDialog::AcceptDialog() { hbc->add_spacer(); ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed)); - set_as_toplevel(true); hide_on_ok = true; set_title(RTR("Alert!")); + + connect("window_input", callable_mp(this, &AcceptDialog::_input_from_window)); } AcceptDialog::~AcceptDialog() { @@ -631,7 +358,7 @@ ConfirmationDialog::ConfirmationDialog() { set_title(RTR("Please Confirm...")); #ifdef TOOLS_ENABLED - set_custom_minimum_size(Size2(200, 70) * EDSCALE); + set_min_size(Size2(200, 70) * EDSCALE); #endif cancel = add_cancel(); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index c474f7849d..b68b4297d7 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -37,91 +37,32 @@ #include "scene/gui/panel.h" #include "scene/gui/popup.h" #include "scene/gui/texture_button.h" - -class WindowDialog : public Popup { - - GDCLASS(WindowDialog, Popup); - - enum DRAG_TYPE { - DRAG_NONE = 0, - DRAG_MOVE = 1, - DRAG_RESIZE_TOP = 1 << 1, - DRAG_RESIZE_RIGHT = 1 << 2, - DRAG_RESIZE_BOTTOM = 1 << 3, - DRAG_RESIZE_LEFT = 1 << 4 - }; - - TextureButton *close_button; - String title; - String xl_title; - int drag_type; - Point2 drag_offset; - Point2 drag_offset_far; - bool resizable; - -#ifdef TOOLS_ENABLED - bool was_editor_dimmed; -#endif - - void _gui_input(const Ref<InputEvent> &p_event); - int _drag_hit_test(const Point2 &pos) const; - -protected: - virtual void _post_popup(); - virtual void _fix_size(); - virtual void _close_pressed() {} - virtual bool has_point(const Point2 &p_point) const; - void _notification(int p_what); - static void _bind_methods(); - - // Not private since used by derived classes signal. - void _closed(); - -public: - TextureButton *get_close_button(); - - void set_title(const String &p_title); - String get_title() const; - void set_resizable(bool p_resizable); - bool get_resizable() const; - - Size2 get_minimum_size() const; - - WindowDialog(); - ~WindowDialog(); -}; - -class PopupDialog : public Popup { - - GDCLASS(PopupDialog, Popup); - -protected: - void _notification(int p_what); - -public: - PopupDialog(); - ~PopupDialog(); -}; +#include "scene/main/window.h" class LineEdit; -class AcceptDialog : public WindowDialog { +class AcceptDialog : public Window { - GDCLASS(AcceptDialog, WindowDialog); + GDCLASS(AcceptDialog, Window); + Window *parent_visible; + Panel *bg; HBoxContainer *hbc; Label *label; Button *ok; bool hide_on_ok; void _custom_action(const String &p_action); - void _close_pressed(); void _update_child_rects(); static bool swap_ok_cancel; + void _input_from_window(const Ref<InputEvent> &p_event); + void _parent_focused(); + protected: - virtual void _post_popup(); + virtual Size2 _get_contents_minimum_size() const; + void _notification(int p_what); static void _bind_methods(); virtual void ok_pressed() {} @@ -131,11 +72,9 @@ protected: // Not private since used by derived classes signal. void _text_entered(const String &p_text); void _ok_pressed(); - void _on_close_pressed(); + void _cancel_pressed(); public: - Size2 get_minimum_size() const; - Label *get_label() { return label; } static void set_swap_ok_cancel(bool p_swap); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 3be77ff4b3..a4f0338f00 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -44,42 +44,46 @@ VBoxContainer *FileDialog::get_vbox() { return vbox; } -void FileDialog::_notification(int p_what) { +void FileDialog::_theme_changed() { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color font_color = vbc->get_theme_color("font_color", "ToolButton"); + Color font_color_hover = vbc->get_theme_color("font_color_hover", "ToolButton"); + Color font_color_pressed = vbc->get_theme_color("font_color_pressed", "ToolButton"); - if (p_what == NOTIFICATION_ENTER_TREE) { - dir_up->set_icon(get_icon("parent_folder")); - refresh->set_icon(get_icon("reload")); - show_hidden->set_icon(get_icon("toggle_hidden")); - } + dir_up->add_theme_color_override("icon_color_normal", font_color); + dir_up->add_theme_color_override("icon_color_hover", font_color_hover); + dir_up->add_theme_color_override("icon_color_pressed", font_color_pressed); - Color font_color = get_color("font_color", "ToolButton"); - Color font_color_hover = get_color("font_color_hover", "ToolButton"); - Color font_color_pressed = get_color("font_color_pressed", "ToolButton"); + refresh->add_theme_color_override("icon_color_normal", font_color); + refresh->add_theme_color_override("icon_color_hover", font_color_hover); + refresh->add_theme_color_override("icon_color_pressed", font_color_pressed); - dir_up->add_color_override("icon_color_normal", font_color); - dir_up->add_color_override("icon_color_hover", font_color_hover); - dir_up->add_color_override("icon_color_pressed", font_color_pressed); + show_hidden->add_theme_color_override("icon_color_normal", font_color); + show_hidden->add_theme_color_override("icon_color_hover", font_color_hover); + show_hidden->add_theme_color_override("icon_color_pressed", font_color_pressed); +} - refresh->add_color_override("icon_color_normal", font_color); - refresh->add_color_override("icon_color_hover", font_color_hover); - refresh->add_color_override("icon_color_pressed", font_color_pressed); +void FileDialog::_notification(int p_what) { - show_hidden->add_color_override("icon_color_normal", font_color); - show_hidden->add_color_override("icon_color_hover", font_color_hover); - show_hidden->add_color_override("icon_color_pressed", font_color_pressed); + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible()) { - } else if (p_what == NOTIFICATION_POPUP_HIDE) { + set_process_unhandled_input(false); + } + } + if (p_what == NOTIFICATION_ENTER_TREE) { - set_process_unhandled_input(false); + dir_up->set_icon(vbc->get_theme_icon("parent_folder")); + refresh->set_icon(vbc->get_theme_icon("reload")); + show_hidden->set_icon(vbc->get_theme_icon("toggle_hidden")); + _theme_changed(); } } void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; - if (k.is_valid() && is_window_modal_on_top()) { + if (k.is_valid() && has_focus()) { if (k->is_pressed()) { @@ -110,7 +114,7 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { } if (handled) - accept_event(); + set_input_as_handled(); } } } @@ -171,7 +175,7 @@ void FileDialog::_post_popup() { update_file_list(); invalidated = false; } - if (mode == MODE_SAVE_FILE) + if (mode == FILE_MODE_SAVE_FILE) file->grab_focus(); else tree->grab_focus(); @@ -179,7 +183,7 @@ void FileDialog::_post_popup() { set_process_unhandled_input(true); // For open dir mode, deselect all items on file dialog open. - if (mode == MODE_OPEN_DIR) { + if (mode == FILE_MODE_OPEN_DIR) { deselect_items(); file_box->set_visible(false); } else { @@ -189,7 +193,7 @@ void FileDialog::_post_popup() { void FileDialog::_action_pressed() { - if (mode == MODE_OPEN_FILES) { + if (mode == FILE_MODE_OPEN_FILES) { TreeItem *ti = tree->get_next_selected(NULL); String fbase = dir_access->get_current_dir(); @@ -211,10 +215,10 @@ void FileDialog::_action_pressed() { String f = dir_access->get_current_dir().plus_file(file->get_text()); - if ((mode == MODE_OPEN_ANY || mode == MODE_OPEN_FILE) && dir_access->file_exists(f)) { + if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) { emit_signal("file_selected", f); hide(); - } else if (mode == MODE_OPEN_ANY || mode == MODE_OPEN_DIR) { + } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) { String path = dir_access->get_current_dir(); @@ -231,7 +235,7 @@ void FileDialog::_action_pressed() { hide(); } - if (mode == MODE_SAVE_FILE) { + if (mode == FILE_MODE_SAVE_FILE) { bool valid = false; @@ -283,7 +287,7 @@ void FileDialog::_action_pressed() { if (!valid) { - exterr->popup_centered_minsize(Size2(250, 80)); + exterr->popup_centered(Size2(250, 80)); return; } @@ -307,7 +311,7 @@ void FileDialog::_cancel_pressed() { bool FileDialog::_is_open_should_be_disabled() { - if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) + if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_SAVE_FILE) return false; TreeItem *ti = tree->get_next_selected(tree->get_root()); @@ -319,13 +323,13 @@ bool FileDialog::_is_open_should_be_disabled() { } // We have something that we can't select? if (!ti) - return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder. + return mode != FILE_MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder. Dictionary d = ti->get_metadata(0); // Opening a file, but selected a folder? Forbidden. - return ((mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES) && d["dir"]) || // Flipped case, also forbidden. - (mode == MODE_OPEN_DIR && !d["dir"]); + return ((mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES) && d["dir"]) || // Flipped case, also forbidden. + (mode == FILE_MODE_OPEN_DIR && !d["dir"]); } void FileDialog::_go_up() { @@ -346,15 +350,15 @@ void FileDialog::deselect_items() { switch (mode) { - case MODE_OPEN_FILE: - case MODE_OPEN_FILES: + case FILE_MODE_OPEN_FILE: + case FILE_MODE_OPEN_FILES: get_ok()->set_text(RTR("Open")); break; - case MODE_OPEN_DIR: + case FILE_MODE_OPEN_DIR: get_ok()->set_text(RTR("Select Current Folder")); break; - case MODE_OPEN_ANY: - case MODE_SAVE_FILE: + case FILE_MODE_OPEN_ANY: + case FILE_MODE_SAVE_FILE: // FIXME: Implement, or refactor to avoid duplication with set_mode break; } @@ -375,7 +379,7 @@ void FileDialog::_tree_selected() { if (!d["dir"]) { file->set_text(d["name"]); - } else if (mode == MODE_OPEN_DIR) { + } else if (mode == FILE_MODE_OPEN_DIR) { get_ok()->set_text(RTR("Select This Folder")); } @@ -393,7 +397,7 @@ void FileDialog::_tree_item_activated() { if (d["dir"]) { dir_access->change_dir(d["name"]); - if (mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES || mode == MODE_OPEN_DIR || mode == MODE_OPEN_ANY) + if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) file->set_text(""); call_deferred("_update_file_list"); call_deferred("_update_dir"); @@ -425,8 +429,8 @@ void FileDialog::update_file_list() { dir_access->list_dir_begin(); TreeItem *root = tree->create_item(); - Ref<Texture2D> folder = get_icon("folder"); - const Color folder_color = get_color("folder_icon_modulate"); + Ref<Texture2D> folder = vbc->get_theme_icon("folder"); + const Color folder_color = vbc->get_theme_color("folder_icon_modulate"); List<String> files; List<String> dirs; @@ -523,8 +527,8 @@ void FileDialog::update_file_list() { ti->set_icon(0, icon); } - if (mode == MODE_OPEN_DIR) { - ti->set_custom_color(0, get_color("files_disabled")); + if (mode == FILE_MODE_OPEN_DIR) { + ti->set_custom_color(0, vbc->get_theme_color("files_disabled")); ti->set_selectable(0, false); } Dictionary d; @@ -661,38 +665,38 @@ bool FileDialog::is_mode_overriding_title() const { return mode_overrides_title; } -void FileDialog::set_mode(Mode p_mode) { +void FileDialog::set_file_mode(FileMode p_mode) { ERR_FAIL_INDEX((int)p_mode, 5); mode = p_mode; switch (mode) { - case MODE_OPEN_FILE: + case FILE_MODE_OPEN_FILE: get_ok()->set_text(RTR("Open")); if (mode_overrides_title) set_title(RTR("Open a File")); makedir->hide(); break; - case MODE_OPEN_FILES: + case FILE_MODE_OPEN_FILES: get_ok()->set_text(RTR("Open")); if (mode_overrides_title) set_title(RTR("Open File(s)")); makedir->hide(); break; - case MODE_OPEN_DIR: + case FILE_MODE_OPEN_DIR: get_ok()->set_text(RTR("Select Current Folder")); if (mode_overrides_title) set_title(RTR("Open a Directory")); makedir->show(); break; - case MODE_OPEN_ANY: + case FILE_MODE_OPEN_ANY: get_ok()->set_text(RTR("Open")); if (mode_overrides_title) set_title(RTR("Open a File or Directory")); makedir->show(); break; - case MODE_SAVE_FILE: + case FILE_MODE_SAVE_FILE: get_ok()->set_text(RTR("Save")); if (mode_overrides_title) set_title(RTR("Save a File")); @@ -700,14 +704,14 @@ void FileDialog::set_mode(Mode p_mode) { break; } - if (mode == MODE_OPEN_FILES) { + if (mode == FILE_MODE_OPEN_FILES) { tree->set_select_mode(Tree::SELECT_MULTI); } else { tree->set_select_mode(Tree::SELECT_SINGLE); } } -FileDialog::Mode FileDialog::get_mode() const { +FileDialog::FileMode FileDialog::get_file_mode() const { return mode; } @@ -741,7 +745,7 @@ void FileDialog::set_access(Access p_access) { void FileDialog::invalidate() { - if (is_visible_in_tree()) { + if (is_visible()) { update_file_list(); invalidated = false; } else { @@ -763,14 +767,14 @@ void FileDialog::_make_dir_confirm() { update_filters(); update_dir(); } else { - mkdirerr->popup_centered_minsize(Size2(250, 50)); + mkdirerr->popup_centered(Size2(250, 50)); } makedirname->set_text(""); // reset label } void FileDialog::_make_dir() { - makedialog->popup_centered_minsize(Size2(250, 80)); + makedialog->popup_centered(Size2(250, 80)); makedirname->grab_focus(); } @@ -826,8 +830,8 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_path", "path"), &FileDialog::set_current_path); ClassDB::bind_method(D_METHOD("set_mode_overrides_title", "override"), &FileDialog::set_mode_overrides_title); ClassDB::bind_method(D_METHOD("is_mode_overriding_title"), &FileDialog::is_mode_overriding_title); - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &FileDialog::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &FileDialog::get_mode); + ClassDB::bind_method(D_METHOD("set_file_mode", "mode"), &FileDialog::set_file_mode); + ClassDB::bind_method(D_METHOD("get_file_mode"), &FileDialog::get_file_mode); ClassDB::bind_method(D_METHOD("get_vbox"), &FileDialog::get_vbox); ClassDB::bind_method(D_METHOD("get_line_edit"), &FileDialog::get_line_edit); ClassDB::bind_method(D_METHOD("set_access", "access"), &FileDialog::set_access); @@ -842,7 +846,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_file_mode", "get_file_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); @@ -854,11 +858,11 @@ void FileDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"))); ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir"))); - BIND_ENUM_CONSTANT(MODE_OPEN_FILE); - BIND_ENUM_CONSTANT(MODE_OPEN_FILES); - BIND_ENUM_CONSTANT(MODE_OPEN_DIR); - BIND_ENUM_CONSTANT(MODE_OPEN_ANY); - BIND_ENUM_CONSTANT(MODE_SAVE_FILE); + BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILE); + BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILES); + BIND_ENUM_CONSTANT(FILE_MODE_OPEN_DIR); + BIND_ENUM_CONSTANT(FILE_MODE_OPEN_ANY); + BIND_ENUM_CONSTANT(FILE_MODE_SAVE_FILE); BIND_ENUM_CONSTANT(ACCESS_RESOURCES); BIND_ENUM_CONSTANT(ACCESS_USERDATA); @@ -884,10 +888,11 @@ FileDialog::FileDialog() { mode_overrides_title = true; - VBoxContainer *vbc = memnew(VBoxContainer); + vbc = memnew(VBoxContainer); add_child(vbc); + vbc->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); - mode = MODE_SAVE_FILE; + mode = FILE_MODE_SAVE_FILE; set_title(RTR("Save a File")); HBoxContainer *hbc = memnew(HBoxContainer); @@ -907,7 +912,7 @@ FileDialog::FileDialog() { dir = memnew(LineEdit); hbc->add_child(dir); - dir->set_h_size_flags(SIZE_EXPAND_FILL); + dir->set_h_size_flags(Control::SIZE_EXPAND_FILL); refresh = memnew(ToolButton); refresh->set_tooltip(RTR("Refresh files.")); @@ -938,11 +943,11 @@ FileDialog::FileDialog() { file_box->add_child(memnew(Label(RTR("File:")))); file = memnew(LineEdit); file->set_stretch_ratio(4); - file->set_h_size_flags(SIZE_EXPAND_FILL); + file->set_h_size_flags(Control::SIZE_EXPAND_FILL); file_box->add_child(file); filter = memnew(OptionButton); filter->set_stretch_ratio(3); - filter->set_h_size_flags(SIZE_EXPAND_FILL); + filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); filter->set_clip_text(true); // too many extensions overflows it file_box->add_child(filter); vbc->add_child(file_box); @@ -961,7 +966,7 @@ FileDialog::FileDialog() { filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected)); confirm_save = memnew(ConfirmationDialog); - confirm_save->set_as_toplevel(true); + // confirm_save->set_as_toplevel(true); add_child(confirm_save); confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); @@ -1024,7 +1029,7 @@ LineEditFileChooser::LineEditFileChooser() { line_edit = memnew(LineEdit); add_child(line_edit); - line_edit->set_h_size_flags(SIZE_EXPAND_FILL); + line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); button = memnew(Button); button->set_text(" .. "); add_child(button); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index a7dc101d12..295ae023d1 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -50,12 +50,12 @@ public: ACCESS_FILESYSTEM }; - enum Mode { - MODE_OPEN_FILE, - MODE_OPEN_FILES, - MODE_OPEN_DIR, - MODE_OPEN_ANY, - MODE_SAVE_FILE + enum FileMode { + FILE_MODE_OPEN_FILE, + FILE_MODE_OPEN_FILES, + FILE_MODE_OPEN_DIR, + FILE_MODE_OPEN_ANY, + FILE_MODE_SAVE_FILE }; typedef Ref<Texture2D> (*GetIconFunc)(const String &); @@ -70,11 +70,12 @@ private: ConfirmationDialog *makedialog; LineEdit *makedirname; + VBoxContainer *vbc; Button *makedir; Access access; //Button *action; VBoxContainer *vbox; - Mode mode; + FileMode mode; LineEdit *dir; HBoxContainer *drives_container; HBoxContainer *shortcuts_container; @@ -131,6 +132,8 @@ private: virtual void _post_popup(); protected: + void _theme_changed(); + void _notification(int p_what); static void _bind_methods(); //bind helpers @@ -153,8 +156,8 @@ public: void set_mode_overrides_title(bool p_override); bool is_mode_overriding_title() const; - void set_mode(Mode p_mode); - Mode get_mode() const; + void set_file_mode(FileMode p_mode); + FileMode get_file_mode() const; VBoxContainer *get_vbox(); LineEdit *get_line_edit() { return file; } @@ -196,7 +199,7 @@ public: LineEditFileChooser(); }; -VARIANT_ENUM_CAST(FileDialog::Mode); +VARIANT_ENUM_CAST(FileDialog::FileMode); VARIANT_ENUM_CAST(FileDialog::Access); #endif diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 6345bfe562..88107f754c 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -76,15 +76,15 @@ void GradientEdit::_show_color_picker() { if (grabbed == -1) return; picker->set_pick_color(points[grabbed].color); - Size2 minsize = popup->get_combined_minimum_size(); + Size2 minsize = popup->get_contents_minimum_size(); bool show_above = false; if (get_global_position().y + get_size().y + minsize.y > get_viewport_rect().size.y) { show_above = true; } if (show_above) { - popup->set_position(get_global_position() - Vector2(0, minsize.y)); + popup->set_position(get_screen_position() - Vector2(0, minsize.y)); } else { - popup->set_position(get_global_position() + Vector2(0, get_size().y)); + popup->set_position(get_screen_position() + Vector2(0, get_size().y)); } popup->popup(); } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 4bc33b220e..fd7935b376 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -30,7 +30,7 @@ #include "graph_edit.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" #include "core/os/keyboard.h" #include "scene/gui/box_container.h" @@ -281,13 +281,13 @@ void GraphEdit::remove_child_notify(Node *p_child) { void GraphEdit::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal"); - port_grab_distance_vertical = get_constant("port_grab_distance_vertical"); + port_grab_distance_horizontal = get_theme_constant("port_grab_distance_horizontal"); + port_grab_distance_vertical = get_theme_constant("port_grab_distance_vertical"); - zoom_minus->set_icon(get_icon("minus")); - zoom_reset->set_icon(get_icon("reset")); - zoom_plus->set_icon(get_icon("more")); - snap_button->set_icon(get_icon("snap")); + zoom_minus->set_icon(get_theme_icon("minus")); + zoom_reset->set_icon(get_theme_icon("reset")); + zoom_plus->set_icon(get_theme_icon("more")); + snap_button->set_icon(get_theme_icon("snap")); } if (p_what == NOTIFICATION_READY) { Size2 hmin = h_scroll->get_combined_minimum_size(); @@ -305,7 +305,7 @@ void GraphEdit::_notification(int p_what) { } if (p_what == NOTIFICATION_DRAW) { - draw_style_box(get_stylebox("bg"), Rect2(Point2(), get_size())); + draw_style_box(get_theme_stylebox("bg"), Rect2(Point2(), get_size())); if (is_using_snap()) { //draw grid @@ -318,8 +318,8 @@ void GraphEdit::_notification(int p_what) { Point2i from = (offset / float(snap)).floor(); Point2i len = (size / float(snap)).floor() + Vector2(1, 1); - Color grid_minor = get_color("grid_minor"); - Color grid_major = get_color("grid_major"); + Color grid_minor = get_theme_color("grid_minor"); + Color grid_major = get_theme_color("grid_major"); for (int i = from.x; i < from.x + len.x; i++) { @@ -357,7 +357,7 @@ void GraphEdit::_notification(int p_what) { bool GraphEdit::_filter_input(const Point2 &p_point) { - Ref<Texture2D> port = get_icon("port", "GraphNode"); + Ref<Texture2D> port = get_theme_icon("port", "GraphNode"); for (int i = get_child_count() - 1; i >= 0; i--) { @@ -389,7 +389,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseButton> mb = p_ev; if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - Ref<Texture2D> port = get_icon("port", "GraphNode"); + Ref<Texture2D> port = get_theme_icon("port", "GraphNode"); Vector2 mpos(mb->get_position().x, mb->get_position().y); for (int i = get_child_count() - 1; i >= 0; i--) { @@ -501,7 +501,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_target = false; top_layer->update(); - Ref<Texture2D> port = get_icon("port", "GraphNode"); + Ref<Texture2D> port = get_theme_icon("port", "GraphNode"); Vector2 mpos = mm->get_position(); for (int i = get_child_count() - 1; i >= 0; i--) { @@ -666,8 +666,8 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const //cubic bezier code float diff = p_to.x - p_from.x; float cp_offset; - int cp_len = get_constant("bezier_len_pos"); - int cp_neg_len = get_constant("bezier_len_neg"); + int cp_len = get_theme_constant("bezier_len_pos"); + int cp_neg_len = get_theme_constant("bezier_len_neg"); if (diff > 0) { cp_offset = MIN(cp_len, diff * 0.5); @@ -697,7 +697,7 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const void GraphEdit::_connections_layer_draw() { - Color activity_color = get_color("activity"); + Color activity_color = get_theme_color("activity"); //draw connections List<List<Connection>::Element *> to_erase; for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { @@ -784,8 +784,8 @@ void GraphEdit::_top_layer_draw() { } if (box_selecting) { - top_layer->draw_rect(box_selecting_rect, get_color("selection_fill")); - top_layer->draw_rect(box_selecting_rect, get_color("selection_stroke"), false); + top_layer->draw_rect(box_selecting_rect, get_theme_color("selection_fill")); + top_layer->draw_rect(box_selecting_rect, get_theme_color("selection_stroke"), false); } } @@ -804,7 +804,7 @@ void GraphEdit::set_selected(Node *p_child) { void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseMotion> mm = p_ev; - if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { + if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && InputFilter::get_singleton()->is_key_pressed(KEY_SPACE)))) { h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); } @@ -823,7 +823,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { // Snapping can be toggled temporarily by holding down Ctrl. // This is done here as to not toggle the grid when holding down Ctrl. - if (is_using_snap() ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + if (is_using_snap() ^ InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) { const int snap = get_snap(); pos = pos.snapped(Vector2(snap, snap)); } @@ -886,7 +886,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && dragging) { - if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + if (!just_selected && drag_accum == Vector2() && InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) { //deselect current node for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -948,7 +948,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { drag_accum = Vector2(); drag_origin = get_local_mouse_position(); just_selected = !gn->is_selected(); - if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + if (!gn->is_selected() && !InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) { for (int i = 0; i < get_child_count(); i++) { GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i)); if (o_gn) @@ -968,7 +968,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } else { if (_filter_input(b->get_position())) return; - if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) + if (InputFilter::get_singleton()->is_key_pressed(KEY_SPACE)) return; box_selecting = true; @@ -1025,16 +1025,16 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { //too difficult to get right //set_zoom(zoom/ZOOM_SCALE); } - if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + if (b->get_button_index() == BUTTON_WHEEL_UP && !InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) { v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); } - if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + if (b->get_button_index() == BUTTON_WHEEL_DOWN && !InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); } - if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { + if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT))) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8); } - if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { + if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT))) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8); } } diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 82e890395a..c28a60ff87 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -117,8 +117,8 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const { void GraphNode::_resort() { - int sep = get_constant("separation"); - Ref<StyleBox> sb = get_stylebox("frame"); + int sep = get_theme_constant("separation"); + Ref<StyleBox> sb = get_theme_stylebox("frame"); bool first = true; Size2 minsize; @@ -169,8 +169,8 @@ void GraphNode::_resort() { bool GraphNode::has_point(const Point2 &p_point) const { if (comment) { - Ref<StyleBox> comment = get_stylebox("comment"); - Ref<Texture2D> resizer = get_icon("resizer"); + Ref<StyleBox> comment = get_theme_stylebox("comment"); + Ref<Texture2D> resizer = get_theme_icon("resizer"); if (Rect2(get_size() - resizer->get_size(), resizer->get_size()).has_point(p_point)) { return true; @@ -195,28 +195,28 @@ void GraphNode::_notification(int p_what) { Ref<StyleBox> sb; if (comment) { - sb = get_stylebox(selected ? "commentfocus" : "comment"); + sb = get_theme_stylebox(selected ? "commentfocus" : "comment"); } else { - sb = get_stylebox(selected ? "selectedframe" : "frame"); + sb = get_theme_stylebox(selected ? "selectedframe" : "frame"); } //sb=sb->duplicate(); //sb->call("set_modulate",modulate); - Ref<Texture2D> port = get_icon("port"); - Ref<Texture2D> close = get_icon("close"); - Ref<Texture2D> resizer = get_icon("resizer"); - int close_offset = get_constant("close_offset"); - int close_h_offset = get_constant("close_h_offset"); - Color close_color = get_color("close_color"); - Color resizer_color = get_color("resizer_color"); - Ref<Font> title_font = get_font("title_font"); - int title_offset = get_constant("title_offset"); - int title_h_offset = get_constant("title_h_offset"); - Color title_color = get_color("title_color"); + Ref<Texture2D> port = get_theme_icon("port"); + Ref<Texture2D> close = get_theme_icon("close"); + Ref<Texture2D> resizer = get_theme_icon("resizer"); + int close_offset = get_theme_constant("close_offset"); + int close_h_offset = get_theme_constant("close_h_offset"); + Color close_color = get_theme_color("close_color"); + Color resizer_color = get_theme_color("resizer_color"); + Ref<Font> title_font = get_theme_font("title_font"); + int title_offset = get_theme_constant("title_offset"); + int title_h_offset = get_theme_constant("title_h_offset"); + Color title_color = get_theme_color("title_color"); Point2i icofs = -port->get_size() * 0.5; - int edgeofs = get_constant("port_offset"); + int edgeofs = get_theme_constant("port_offset"); icofs.y += sb->get_margin(MARGIN_TOP); draw_style_box(sb, Rect2(Point2(), get_size())); @@ -227,10 +227,10 @@ void GraphNode::_notification(int p_what) { } break; case OVERLAY_BREAKPOINT: { - draw_style_box(get_stylebox("breakpoint"), Rect2(Point2(), get_size())); + draw_style_box(get_theme_stylebox("breakpoint"), Rect2(Point2(), get_size())); } break; case OVERLAY_POSITION: { - draw_style_box(get_stylebox("position"), Rect2(Point2(), get_size())); + draw_style_box(get_theme_stylebox("position"), Rect2(Point2(), get_size())); } break; } @@ -370,16 +370,16 @@ Color GraphNode::get_slot_color_right(int p_idx) const { Size2 GraphNode::get_minimum_size() const { - Ref<Font> title_font = get_font("title_font"); + Ref<Font> title_font = get_theme_font("title_font"); - int sep = get_constant("separation"); - Ref<StyleBox> sb = get_stylebox("frame"); + int sep = get_theme_constant("separation"); + Ref<StyleBox> sb = get_theme_stylebox("frame"); bool first = true; Size2 minsize; minsize.x = title_font->get_string_size(title).x; if (show_close) { - Ref<Texture2D> close = get_icon("close"); + Ref<Texture2D> close = get_theme_icon("close"); minsize.x += sep + close->get_width(); } @@ -464,10 +464,10 @@ bool GraphNode::is_close_button_visible() const { void GraphNode::_connpos_update() { - int edgeofs = get_constant("port_offset"); - int sep = get_constant("separation"); + int edgeofs = get_theme_constant("port_offset"); + int sep = get_theme_constant("separation"); - Ref<StyleBox> sb = get_stylebox("frame"); + Ref<StyleBox> sb = get_theme_stylebox("frame"); conn_input_cache.clear(); conn_output_cache.clear(); int vofs = 0; @@ -606,7 +606,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) { return; } - Ref<Texture2D> resizer = get_icon("resizer"); + Ref<Texture2D> resizer = get_theme_icon("resizer"); if (resizable && mpos.x > get_size().x - resizer->get_width() && mpos.y > get_size().y - resizer->get_height()) { diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index 0028093a95..16f6fd0111 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -41,8 +41,8 @@ void GridContainer::_notification(int p_what) { Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set. Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set. - int hsep = get_constant("hseparation"); - int vsep = get_constant("vseparation"); + int hsep = get_theme_constant("hseparation"); + int vsep = get_theme_constant("vseparation"); int max_col = MIN(get_child_count(), columns); int max_row = ceil((float)get_child_count() / (float)columns); @@ -200,8 +200,8 @@ Size2 GridContainer::get_minimum_size() const { Map<int, int> col_minw; Map<int, int> row_minh; - int hsep = get_constant("hseparation"); - int vsep = get_constant("vseparation"); + int hsep = get_theme_constant("hseparation"); + int vsep = get_theme_constant("vseparation"); int max_row = 0; int max_col = 0; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 5e662b8df0..2db44d0b66 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -495,7 +495,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { search_string = ""; //any mousepress cancels Vector2 pos = mb->get_position(); - Ref<StyleBox> bg = get_stylebox("bg"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); pos -= bg->get_offset(); pos.y += scroll_bar->get_value(); @@ -820,7 +820,7 @@ void ItemList::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> bg = get_stylebox("bg"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); int mw = scroll_bar->get_minimum_size().x; scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw); @@ -837,18 +837,18 @@ void ItemList::_notification(int p_what) { draw_style_box(bg, Rect2(Point2(), size)); - int hseparation = get_constant("hseparation"); - int vseparation = get_constant("vseparation"); - int icon_margin = get_constant("icon_margin"); - int line_separation = get_constant("line_separation"); + int hseparation = get_theme_constant("hseparation"); + int vseparation = get_theme_constant("vseparation"); + int icon_margin = get_theme_constant("icon_margin"); + int line_separation = get_theme_constant("line_separation"); - Ref<StyleBox> sbsel = has_focus() ? get_stylebox("selected_focus") : get_stylebox("selected"); - Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused"); + Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox("selected_focus") : get_theme_stylebox("selected"); + Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox("cursor") : get_theme_stylebox("cursor_unfocused"); - Ref<Font> font = get_font("font"); - Color guide_color = get_color("guide_color"); - Color font_color = get_color("font_color"); - Color font_color_selected = get_color("font_color_selected"); + Ref<Font> font = get_theme_font("font"); + Color guide_color = get_theme_color("guide_color"); + Color font_color = get_theme_color("font_color"); + Color font_color_selected = get_theme_color("font_color_selected"); int font_height = font->get_height(); Vector<int> line_size_cache; Vector<int> line_limit_cache; @@ -860,7 +860,7 @@ void ItemList::_notification(int p_what) { if (has_focus()) { VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true); - draw_style_box(get_stylebox("bg_focus"), Rect2(Point2(), size)); + draw_style_box(get_theme_stylebox("bg_focus"), Rect2(Point2(), size)); VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false); } @@ -1251,7 +1251,7 @@ void ItemList::_scroll_changed(double) { int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { Vector2 pos = p_pos; - Ref<StyleBox> bg = get_stylebox("bg"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); pos -= bg->get_offset(); pos.y += scroll_bar->get_value(); @@ -1286,7 +1286,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const { return true; Vector2 pos = p_pos; - Ref<StyleBox> bg = get_stylebox("bg"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); pos -= bg->get_offset(); pos.y += scroll_bar->get_value(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index c900b35d65..ef1bb958f6 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -65,7 +65,7 @@ bool Label::is_uppercase() const { int Label::get_line_height() const { - return get_font("font")->get_height(); + return get_theme_font("font")->get_height(); } void Label::_notification(int p_what) { @@ -94,14 +94,14 @@ void Label::_notification(int p_what) { Size2 string_size; Size2 size = get_size(); - Ref<StyleBox> style = get_stylebox("normal"); - Ref<Font> font = get_font("font"); - Color font_color = get_color("font_color"); - Color font_color_shadow = get_color("font_color_shadow"); - bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); - int line_spacing = get_constant("line_spacing"); - Color font_outline_modulate = get_color("font_outline_modulate"); + Ref<StyleBox> style = get_theme_stylebox("normal"); + Ref<Font> font = get_theme_font("font"); + Color font_color = get_theme_color("font_color"); + Color font_color_shadow = get_theme_color("font_color_shadow"); + bool use_outline = get_theme_constant("shadow_as_outline"); + Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); + int line_spacing = get_theme_constant("line_spacing"); + Color font_outline_modulate = get_theme_color("font_outline_modulate"); style->draw(ci, Rect2(Point2(0, 0), get_size())); @@ -300,7 +300,7 @@ void Label::_notification(int p_what) { Size2 Label::get_minimum_size() const { - Size2 min_style = get_stylebox("normal")->get_minimum_size(); + Size2 min_style = get_theme_stylebox("normal")->get_minimum_size(); // don't want to mutable everything if (word_cache_dirty) { @@ -319,7 +319,7 @@ Size2 Label::get_minimum_size() const { int Label::get_longest_line_width() const { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); real_t max_line_width = 0; real_t line_width = 0; @@ -363,9 +363,9 @@ int Label::get_line_count() const { int Label::get_visible_line_count() const { - int line_spacing = get_constant("line_spacing"); - int font_h = get_font("font")->get_height() + line_spacing; - int lines_visible = (get_size().height - get_stylebox("normal")->get_minimum_size().height + line_spacing) / font_h; + int line_spacing = get_theme_constant("line_spacing"); + int font_h = get_theme_font("font")->get_height() + line_spacing; + int lines_visible = (get_size().height - get_theme_stylebox("normal")->get_minimum_size().height + line_spacing) / font_h; if (lines_visible > line_count) lines_visible = line_count; @@ -387,20 +387,20 @@ void Label::regenerate_word_cache() { int width; if (autowrap) { - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); width = MAX(get_size().width, get_custom_minimum_size().width) - style->get_minimum_size().width; } else { width = get_longest_line_width(); } - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); real_t current_word_size = 0; int word_pos = 0; real_t line_width = 0; int space_count = 0; real_t space_width = font->get_char_size(' ').width; - int line_spacing = get_constant("line_spacing"); + int line_spacing = get_theme_constant("line_spacing"); line_count = 1; total_char_cache = 0; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 7ee4dab3c9..734e27b1b6 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -36,12 +36,12 @@ #include "core/print_string.h" #include "core/translation.h" #include "label.h" - +#include "servers/display_server.h" #ifdef TOOLS_ENABLED #include "editor/editor_scale.h" #include "editor/editor_settings.h" #endif - +#include "scene/main/window.h" static bool _is_text_char(CharType c) { return !is_symbol(c); @@ -56,7 +56,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); - menu->set_scale(get_global_transform().get_scale()); + //menu->set_scale(get_global_transform().get_scale()); menu->popup(); grab_focus(); accept_event(); @@ -127,8 +127,8 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { selection.creating = false; selection.doubleclick = false; - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); } update(); @@ -304,8 +304,8 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case KEY_ENTER: { emit_signal("text_entered", text); - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->hide_virtual_keyboard(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_hide(); } break; @@ -552,10 +552,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; case KEY_MENU: { if (context_menu_enabled) { - Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_font("font")->get_height()) / 2); + Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_theme_font("font")->get_height()) / 2); menu->set_position(get_global_transform().xform(pos)); menu->set_size(Vector2(1, 1)); - menu->set_scale(get_global_transform().get_scale()); + // menu->set_scale(get_global_transform().get_scale()); menu->popup(); menu->grab_focus(); } @@ -629,7 +629,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { set_cursor_at_pixel_pos(p_point.x); int selected = selection.end - selection.begin; - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); if (font != NULL) { for (int i = selection.begin; i < selection.end; i++) cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width; @@ -654,8 +654,8 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { if (!clear_button_enabled || !has_point(p_pos)) { return false; } - Ref<Texture2D> icon = Control::get_icon("clear"); - int x_ofs = get_stylebox("normal")->get_offset().x; + Ref<Texture2D> icon = Control::get_theme_icon("clear"); + int x_ofs = get_theme_stylebox("normal")->get_offset().x; return p_pos.x > get_size().width - icon->get_width() - x_ofs; } @@ -685,12 +685,12 @@ void LineEdit::_notification(int p_what) { update_placeholder_width(); update(); } break; - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + case NOTIFICATION_WM_FOCUS_IN: { window_has_focus = true; draw_caret = true; update(); } break; - case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_FOCUS_OUT: { window_has_focus = false; draw_caret = false; update(); @@ -709,19 +709,19 @@ void LineEdit::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); if (!is_editable()) { - style = get_stylebox("read_only"); + style = get_theme_stylebox("read_only"); draw_caret = false; } - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); style->draw(ci, Rect2(Point2(), size)); if (has_focus()) { - get_stylebox("focus")->draw(ci, Rect2(Point2(), size)); + get_theme_stylebox("focus")->draw(ci, Rect2(Point2(), size)); } int x_ofs = 0; @@ -756,10 +756,10 @@ void LineEdit::_notification(int p_what) { int font_ascent = font->get_ascent(); - Color selection_color = get_color("selection_color"); - Color font_color = is_editable() ? get_color("font_color") : get_color("font_color_uneditable"); - Color font_color_selected = get_color("font_color_selected"); - Color cursor_color = get_color("cursor_color"); + Color selection_color = get_theme_color("selection_color"); + Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_color_uneditable"); + Color font_color_selected = get_theme_color("font_color_selected"); + Color cursor_color = get_theme_color("cursor_color"); const String &t = using_placeholder ? placeholder_translated : text; // Draw placeholder color. @@ -768,13 +768,13 @@ void LineEdit::_notification(int p_what) { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9); if (display_clear_icon) { if (clear_button_status.press_attempt && clear_button_status.pressing_inside) { - color_icon = get_color("clear_button_color_pressed"); + color_icon = get_theme_color("clear_button_color_pressed"); } else { - color_icon = get_color("clear_button_color"); + color_icon = get_theme_color("clear_button_color"); } } @@ -913,9 +913,10 @@ void LineEdit::_notification(int p_what) { } if (has_focus()) { - - OS::get_singleton()->set_ime_active(true); - OS::get_singleton()->set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + caret_height)); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); + DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + caret_height), get_viewport()->get_window_id()); + } } } break; case NOTIFICATION_FOCUS_ENTER: { @@ -926,12 +927,14 @@ void LineEdit::_notification(int p_what) { draw_caret = true; } - OS::get_singleton()->set_ime_active(true); - Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height; - OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); + Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height; + DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); + } - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); } break; case NOTIFICATION_FOCUS_EXIT: { @@ -940,20 +943,22 @@ void LineEdit::_notification(int p_what) { caret_blink_timer->stop(); } - OS::get_singleton()->set_ime_position(Point2()); - OS::get_singleton()->set_ime_active(false); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); + DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); + } ime_text = ""; ime_selection = Point2(); - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->hide_virtual_keyboard(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_hide(); } break; case MainLoop::NOTIFICATION_OS_IME_UPDATE: { if (has_focus()) { - ime_text = OS::get_singleton()->get_ime_text(); - ime_selection = OS::get_singleton()->get_ime_selection(); + ime_text = DisplayServer::get_singleton()->ime_get_text(); + ime_selection = DisplayServer::get_singleton()->ime_get_selection(); update(); } } break; @@ -963,14 +968,14 @@ void LineEdit::_notification(int p_what) { void LineEdit::copy_text() { if (selection.enabled && !pass) { - OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); + DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin)); } } void LineEdit::cut_text() { if (selection.enabled && !pass) { - OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); + DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin)); selection_delete(); } } @@ -978,7 +983,7 @@ void LineEdit::cut_text() { void LineEdit::paste_text() { // Strip escape characters like \n and \t as they can't be displayed on LineEdit. - String paste_buffer = OS::get_singleton()->get_clipboard().strip_escapes(); + String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes(); if (paste_buffer != "") { @@ -1054,13 +1059,13 @@ void LineEdit::shift_selection_check_post(bool p_shift) { void LineEdit::set_cursor_at_pixel_pos(int p_x) { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); int ofs = window_pos; - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; - int r_icon_width = Control::get_icon("clear")->get_width(); + int r_icon_width = Control::get_theme_icon("clear")->get_width(); switch (align) { @@ -1108,13 +1113,13 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { int LineEdit::get_cursor_pixel_pos() { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); int ofs = window_pos; - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; - int r_icon_width = Control::get_icon("clear")->get_width(); + int r_icon_width = Control::get_theme_icon("clear")->get_width(); switch (align) { @@ -1201,7 +1206,7 @@ void LineEdit::delete_char() { if ((text.length() <= 0) || (cursor_pos == 0)) return; - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); if (font != NULL) { cached_width -= font->get_char_size(pass ? secret_character[0] : text[cursor_pos - 1]).width; } @@ -1220,7 +1225,7 @@ void LineEdit::delete_char() { void LineEdit::delete_text(int p_from_column, int p_to_column) { if (text.size() > 0) { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); if (font != NULL) { for (int i = p_from_column; i < p_to_column; i++) cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width; @@ -1318,8 +1323,8 @@ void LineEdit::set_cursor_position(int p_pos) { return; } - Ref<StyleBox> style = get_stylebox("normal"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> style = get_theme_stylebox("normal"); + Ref<Font> font = get_theme_font("font"); if (cursor_pos <= window_pos) { // Adjust window if cursor goes too much to the left. @@ -1329,7 +1334,7 @@ void LineEdit::set_cursor_position(int p_pos) { int window_width = get_size().width - style->get_minimum_size().width; bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; window_width -= r_icon->get_width(); } @@ -1404,14 +1409,14 @@ void LineEdit::clear_internal() { Size2 LineEdit::get_minimum_size() const { - Ref<StyleBox> style = get_stylebox("normal"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> style = get_theme_stylebox("normal"); + Ref<Font> font = get_theme_font("font"); Size2 min_size; // Minimum size of text. int space_size = font->get_char_size(' ').x; - min_size.width = get_constant("minimum_spaces") * space_size; + min_size.width = get_theme_constant("minimum_spaces") * space_size; if (expand_to_text_length) { // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end. @@ -1422,8 +1427,8 @@ Size2 LineEdit::get_minimum_size() const { // Take icons into account. if (!text.empty() && is_editable() && clear_button_enabled) { - min_size.width = MAX(min_size.width, Control::get_icon("clear")->get_width()); - min_size.height = MAX(min_size.height, Control::get_icon("clear")->get_height()); + min_size.width = MAX(min_size.width, Control::get_theme_icon("clear")->get_width()); + min_size.height = MAX(min_size.height, Control::get_theme_icon("clear")->get_height()); } if (right_icon.is_valid()) { min_size.width = MAX(min_size.width, right_icon->get_width()); @@ -1702,7 +1707,7 @@ void LineEdit::_emit_text_change() { } void LineEdit::update_cached_width() { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); cached_width = 0; if (font != NULL) { String text = get_text(); @@ -1713,7 +1718,7 @@ void LineEdit::update_cached_width() { } void LineEdit::update_placeholder_width() { - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); cached_placeholder_width = 0; if (font != NULL) { for (int i = 0; i < placeholder_translated.length(); i++) { diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 4b8054bac6..3dffa06b49 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -54,7 +54,7 @@ LinkButton::UnderlineMode LinkButton::get_underline_mode() const { Size2 LinkButton::get_minimum_size() const { - return get_font("font")->get_string_size(text); + return get_theme_font("font")->get_string_size(text); } void LinkButton::_notification(int p_what) { @@ -72,29 +72,29 @@ void LinkButton::_notification(int p_what) { case DRAW_NORMAL: { - color = get_color("font_color"); + color = get_theme_color("font_color"); do_underline = underline_mode == UNDERLINE_MODE_ALWAYS; } break; case DRAW_HOVER_PRESSED: case DRAW_PRESSED: { - if (has_color("font_color_pressed")) - color = get_color("font_color_pressed"); + if (has_theme_color("font_color_pressed")) + color = get_theme_color("font_color_pressed"); else - color = get_color("font_color"); + color = get_theme_color("font_color"); do_underline = underline_mode != UNDERLINE_MODE_NEVER; } break; case DRAW_HOVER: { - color = get_color("font_color_hover"); + color = get_theme_color("font_color_hover"); do_underline = underline_mode != UNDERLINE_MODE_NEVER; } break; case DRAW_DISABLED: { - color = get_color("font_color_disabled"); + color = get_theme_color("font_color_disabled"); do_underline = underline_mode == UNDERLINE_MODE_ALWAYS; } break; @@ -102,16 +102,16 @@ void LinkButton::_notification(int p_what) { if (has_focus()) { - Ref<StyleBox> style = get_stylebox("focus"); + Ref<StyleBox> style = get_theme_stylebox("focus"); style->draw(ci, Rect2(Point2(), size)); } - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); draw_string(font, Vector2(0, font->get_ascent()), text, color); if (do_underline) { - int underline_spacing = get_constant("underline_spacing"); + int underline_spacing = get_theme_constant("underline_spacing"); int width = font->get_string_size(text).width; int y = font->get_ascent() + underline_spacing; diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 53373fc297..1cd4ff4ff8 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -32,10 +32,10 @@ Size2 MarginContainer::get_minimum_size() const { - int margin_left = get_constant("margin_left"); - int margin_top = get_constant("margin_top"); - int margin_right = get_constant("margin_right"); - int margin_bottom = get_constant("margin_bottom"); + int margin_left = get_theme_constant("margin_left"); + int margin_top = get_theme_constant("margin_top"); + int margin_right = get_theme_constant("margin_right"); + int margin_bottom = get_theme_constant("margin_bottom"); Size2 max; @@ -67,10 +67,10 @@ void MarginContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { - int margin_left = get_constant("margin_left"); - int margin_top = get_constant("margin_top"); - int margin_right = get_constant("margin_right"); - int margin_bottom = get_constant("margin_bottom"); + int margin_left = get_theme_constant("margin_left"); + int margin_top = get_theme_constant("margin_top"); + int margin_right = get_theme_constant("margin_right"); + int margin_bottom = get_theme_constant("margin_bottom"); Size2 s = get_size(); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 2b163187c5..a7d1f64e93 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -31,7 +31,7 @@ #include "menu_button.h" #include "core/os/keyboard.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { @@ -43,23 +43,34 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { if (!get_parent() || !is_visible_in_tree() || is_disabled()) return; - bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)); - - if (popup->activate_item_by_event(p_event, global_only)) + //bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)); + //if (popup->activate_item_by_event(p_event, global_only)) + // accept_event(); + if (popup->activate_item_by_event(p_event, false)) accept_event(); } } void MenuButton::pressed() { - emit_signal("about_to_show"); + { + Window *w = Object::cast_to<Window>(get_viewport()); + if (w && !w->is_embedding_subwindows()) { + print_line("windowpos: " + w->get_position()); + } + } Size2 size = get_size(); - Point2 gp = get_global_position(); - popup->set_global_position(gp + Size2(0, size.height * get_global_transform().get_scale().y)); + Point2 gp = get_screen_position(); + + print_line("screenpos: " + gp); + gp.y += get_size().y; + + popup->set_position(gp); + popup->set_size(Size2(size.width, 0)); - popup->set_scale(get_global_transform().get_scale()); - popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size())); + popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size())); + popup->take_mouse_focus(); popup->popup(); } @@ -116,7 +127,7 @@ void MenuButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover"); - ADD_SIGNAL(MethodInfo("about_to_show")); + ADD_SIGNAL(MethodInfo("about_to_popup")); } void MenuButton::set_disable_shortcuts(bool p_disabled) { @@ -137,8 +148,7 @@ MenuButton::MenuButton() { popup = memnew(PopupMenu); popup->hide(); add_child(popup); - popup->set_pass_on_modal_close_click(false); - popup->connect("about_to_show", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); // For when switching from another MenuButton. + popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); // For when switching from another MenuButton. popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false)); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index c185761beb..30ecd651b1 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -36,12 +36,12 @@ Size2 OptionButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); - if (has_icon("arrow")) { - const Size2 padding = get_stylebox("normal")->get_minimum_size(); - const Size2 arrow_size = Control::get_icon("arrow")->get_size(); + if (has_theme_icon("arrow")) { + const Size2 padding = get_theme_stylebox("normal")->get_minimum_size(); + const Size2 arrow_size = Control::get_theme_icon("arrow")->get_size(); Size2 content_size = minsize - padding; - content_size.width += arrow_size.width + get_constant("hseparation"); + content_size.width += arrow_size.width + get_theme_constant("hseparation"); content_size.height = MAX(content_size.height, arrow_size.height); minsize = content_size + padding; @@ -55,37 +55,37 @@ void OptionButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { - if (!has_icon("arrow")) + if (!has_theme_icon("arrow")) return; RID ci = get_canvas_item(); - Ref<Texture2D> arrow = Control::get_icon("arrow"); + Ref<Texture2D> arrow = Control::get_theme_icon("arrow"); Color clr = Color(1, 1, 1); - if (get_constant("modulate_arrow")) { + if (get_theme_constant("modulate_arrow")) { switch (get_draw_mode()) { case DRAW_PRESSED: - clr = get_color("font_color_pressed"); + clr = get_theme_color("font_color_pressed"); break; case DRAW_HOVER: - clr = get_color("font_color_hover"); + clr = get_theme_color("font_color_hover"); break; case DRAW_DISABLED: - clr = get_color("font_color_disabled"); + clr = get_theme_color("font_color_disabled"); break; default: - clr = get_color("font_color"); + clr = get_theme_color("font_color"); } } Size2 size = get_size(); - Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); + Point2 ofs(size.width - arrow->get_width() - get_theme_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); arrow->draw(ci, ofs, clr); } break; case NOTIFICATION_THEME_CHANGED: { - if (has_icon("arrow")) { - _set_internal_margin(MARGIN_RIGHT, Control::get_icon("arrow")->get_width()); + if (has_theme_icon("arrow")) { + _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width()); } } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -109,9 +109,8 @@ void OptionButton::_selected(int p_which) { void OptionButton::pressed() { Size2 size = get_size(); - popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y)); + popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); popup->set_size(Size2(size.width, 0)); - popup->set_scale(get_global_transform().get_scale()); popup->popup(); } @@ -351,15 +350,15 @@ OptionButton::OptionButton() { set_toggle_mode(true); set_text_align(ALIGN_LEFT); set_action_mode(ACTION_MODE_BUTTON_PRESS); - if (has_icon("arrow")) { - _set_internal_margin(MARGIN_RIGHT, Control::get_icon("arrow")->get_width()); + if (has_theme_icon("arrow")) { + _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width()); } popup = memnew(PopupMenu); popup->hide(); add_child(popup); - popup->set_pass_on_modal_close_click(false); - popup->set_notify_transform(true); + // popup->set_pass_on_modal_close_click(false); + // popup->set_notify_transform(true); popup->set_allow_search(true); popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected)); popup->connect("id_focused", callable_mp(this, &OptionButton::_focused)); diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index 0356607071..ae51463a15 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -36,11 +36,25 @@ void Panel::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); - Ref<StyleBox> style = get_stylebox("panel"); + Ref<StyleBox> style = mode == MODE_BACKGROUND ? get_theme_stylebox("panel") : get_theme_stylebox("panel_fg"); style->draw(ci, Rect2(Point2(), get_size())); } } +void Panel::set_mode(Mode p_mode) { + mode = p_mode; + update(); +} +Panel::Mode Panel::get_mode() const { + return mode; +} + +void Panel::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Panel::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &Panel::get_mode); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Background,Foreground"), "set_mode", "get_mode"); +} Panel::Panel() { // Has visible stylebox, so stop by default. set_mouse_filter(MOUSE_FILTER_STOP); diff --git a/scene/gui/panel.h b/scene/gui/panel.h index 3538126d22..739c64c0a6 100644 --- a/scene/gui/panel.h +++ b/scene/gui/panel.h @@ -37,12 +37,26 @@ class Panel : public Control { GDCLASS(Panel, Control); +public: + enum Mode { + MODE_BACKGROUND, + MODE_FOREGROUND + }; + +private: + Mode mode = MODE_BACKGROUND; + protected: void _notification(int p_what); + static void _bind_methods(); public: + void set_mode(Mode p_mode); + Mode get_mode() const; + Panel(); ~Panel(); }; +VARIANT_ENUM_CAST(Panel::Mode) #endif diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 6cf23b8a32..62b9296409 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -34,16 +34,16 @@ Size2 PanelContainer::get_minimum_size() const { Ref<StyleBox> style; - if (has_stylebox("panel")) - style = get_stylebox("panel"); + if (has_theme_stylebox("panel")) + style = get_theme_stylebox("panel"); else - style = get_stylebox("panel", "PanelContainer"); + style = get_theme_stylebox("panel", "PanelContainer"); Size2 ms; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c || !c->is_visible_in_tree()) + if (!c || !c->is_visible()) continue; if (c->is_set_as_toplevel()) continue; @@ -65,10 +65,10 @@ void PanelContainer::_notification(int p_what) { RID ci = get_canvas_item(); Ref<StyleBox> style; - if (has_stylebox("panel")) - style = get_stylebox("panel"); + if (has_theme_stylebox("panel")) + style = get_theme_stylebox("panel"); else - style = get_stylebox("panel", "PanelContainer"); + style = get_theme_stylebox("panel", "PanelContainer"); style->draw(ci, Rect2(Point2(), get_size())); } @@ -77,10 +77,10 @@ void PanelContainer::_notification(int p_what) { Ref<StyleBox> style; - if (has_stylebox("panel")) - style = get_stylebox("panel"); + if (has_theme_stylebox("panel")) + style = get_theme_stylebox("panel"); else - style = get_stylebox("panel", "PanelContainer"); + style = get_theme_stylebox("panel", "PanelContainer"); Size2 size = get_size(); Point2 ofs; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 64ef4a01f6..6edafc65a0 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -32,227 +32,131 @@ #include "core/engine.h" #include "core/os/keyboard.h" +#include "scene/gui/panel.h" -void Popup::_gui_input(Ref<InputEvent> p_event) { -} - -void Popup::_notification(int p_what) { - - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (popped_up && !is_visible_in_tree()) { - popped_up = false; - notification(NOTIFICATION_POPUP_HIDE); - emit_signal("popup_hide"); - } - - update_configuration_warning(); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - if (popped_up) { - popped_up = false; - notification(NOTIFICATION_POPUP_HIDE); - emit_signal("popup_hide"); - } - } - - if (p_what == NOTIFICATION_ENTER_TREE) { -//small helper to make editing of these easier in editor -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { - //edited on editor - set_as_toplevel(false); - } else -#endif - if (is_visible()) { - hide(); - } +void Popup::_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) { + _close_pressed(); } } -void Popup::_fix_size() { - - Point2 pos = get_global_position(); - Size2 size = get_size() * get_scale(); - Point2 window_size = get_viewport_rect().size - get_viewport_transform().get_origin(); - - if (pos.x + size.width > window_size.width) - pos.x = window_size.width - size.width; - if (pos.x < 0) - pos.x = 0; +void Popup::_parent_focused() { - if (pos.y + size.height > window_size.height) - pos.y = window_size.height - size.height; - if (pos.y < 0) - pos.y = 0; - if (pos != get_position()) - set_global_position(pos); + _close_pressed(); } +void Popup::_notification(int p_what) { -void Popup::set_as_minsize() { - - Size2 total_minsize; - - for (int i = 0; i < get_child_count(); i++) { - - Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) - continue; - if (!c->is_visible()) - continue; - - Size2 minsize = c->get_combined_minimum_size(); - - for (int j = 0; j < 2; j++) { - - Margin m_beg = Margin(0 + j); - Margin m_end = Margin(2 + j); - - float margin_begin = c->get_margin(m_beg); - float margin_end = c->get_margin(m_end); - float anchor_begin = c->get_anchor(m_beg); - float anchor_end = c->get_anchor(m_end); - - minsize[j] += margin_begin * (ANCHOR_END - anchor_begin) + margin_end * anchor_end; - } - - total_minsize.width = MAX(total_minsize.width, minsize.width); - total_minsize.height = MAX(total_minsize.height, minsize.height); + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + + parent_visible = get_parent_visible_window(); + if (parent_visible) { + parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + } + } else { + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_visible = nullptr; + } + + emit_signal("popup_hide"); + } + + } break; + case NOTIFICATION_EXIT_TREE: { + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_visible = nullptr; + } + } break; + case NOTIFICATION_WM_CLOSE_REQUEST: { + _close_pressed(); + + } break; } - - set_size(total_minsize); } -void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) { - - Size2 popup_size = p_size; - Size2 window_size = get_viewport_rect().size; - - // clamp popup size in each dimension if window size is too small (using fallback ratio) - popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x); - popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y); - - popup_centered(popup_size); -} +void Popup::_close_pressed() { -void Popup::popup_centered_minsize(const Size2 &p_minsize) { - - set_custom_minimum_size(p_minsize); - _fix_size(); - popup_centered(); -} + Window *parent_window = parent_visible; + if (parent_visible) { + parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_visible = nullptr; + } -void Popup::popup_centered(const Size2 &p_size) { + call_deferred("hide"); - Rect2 rect; - Size2 window_size = get_viewport_rect().size; - rect.size = p_size == Size2() ? get_size() : p_size; - rect.position = ((window_size - rect.size) / 2.0).floor(); + emit_signal("cancelled"); - _popup(rect, true); + if (parent_window) { + //parent_window->grab_focus(); + } } -void Popup::popup_centered_ratio(float p_screen_ratio) { - - Rect2 rect; - Size2 window_size = get_viewport_rect().size; - rect.size = (window_size * p_screen_ratio).floor(); - rect.position = ((window_size - rect.size) / 2.0).floor(); - - _popup(rect, true); +void Popup::set_as_minsize() { + set_size(get_contents_minimum_size()); } +void Popup::_bind_methods() { -void Popup::popup(const Rect2 &p_bounds) { - - _popup(p_bounds); + ADD_SIGNAL(MethodInfo("popup_hide")); } -void Popup::_popup(const Rect2 &p_bounds, const bool p_centered) { - - emit_signal("about_to_show"); - show_modal(exclusive); - - // Fit the popup into the optionally provided bounds. - if (!p_bounds.has_no_area()) { - set_size(p_bounds.size); +Rect2i Popup::_popup_adjust_rect() const { + ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); + Rect2i parent = get_usable_parent_rect(); - // check if p_bounds.size was using an outdated cached values - if (p_centered && p_bounds.size != get_size()) { - set_position(p_bounds.position - ((get_size() - p_bounds.size) / 2.0).floor()); - } else { - set_position(p_bounds.position); - } + if (parent == Rect2i()) { + return Rect2i(); } - _fix_size(); - - Control *focusable = find_next_valid_focus(); - - if (focusable) - focusable->grab_focus(); - - _post_popup(); - notification(NOTIFICATION_POST_POPUP); - popped_up = true; -} -void Popup::set_exclusive(bool p_exclusive) { + Rect2i current(get_position(), get_size()); - exclusive = p_exclusive; -} - -bool Popup::is_exclusive() const { + if (current.position.x + current.size.x > parent.position.x + parent.size.x) { + current.position.x = parent.position.x + parent.size.x - current.size.x; + } - return exclusive; -} + if (current.position.x < parent.position.x) { + current.position.x = parent.position.x; + } -void Popup::_bind_methods() { + if (current.position.y + current.size.y > parent.position.y + parent.size.y) { + current.position.y = parent.position.y + parent.size.y - current.size.y; + } - ClassDB::bind_method(D_METHOD("set_as_minsize"), &Popup::set_as_minsize); - ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2())); - ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75)); - ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2())); - ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75)); - ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2())); - ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive); - ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive); - ADD_SIGNAL(MethodInfo("about_to_show")); - ADD_SIGNAL(MethodInfo("popup_hide")); - ADD_GROUP("Popup", "popup_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "popup_exclusive"), "set_exclusive", "is_exclusive"); + if (current.position.y < parent.position.y) { + current.position.y = parent.position.y; + } - BIND_CONSTANT(NOTIFICATION_POST_POPUP); - BIND_CONSTANT(NOTIFICATION_POPUP_HIDE); + return current; } Popup::Popup() { - set_as_toplevel(true); - exclusive = false; - popped_up = false; - hide(); -} - -String Popup::get_configuration_warning() const { + parent_visible = nullptr; - if (is_visible_in_tree()) { - return TTR("Popups will hide by default unless you call popup() or any of the popup*() functions. Making them visible for editing is fine, but they will hide upon running."); - } + set_wrap_controls(true); + set_visible(false); + set_transient(true); + set_flag(FLAG_BORDERLESS, true); + set_flag(FLAG_RESIZE_DISABLED, true); - return String(); + connect("window_input", callable_mp(this, &Popup::_input_from_window)); } Popup::~Popup() { } -Size2 PopupPanel::get_minimum_size() const { +Size2 PopupPanel::_get_contents_minimum_size() const { - Ref<StyleBox> p = get_stylebox("panel"); + Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name()); Size2 ms; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) + if (!c || c == panel) continue; if (c->is_set_as_toplevel()) @@ -268,7 +172,7 @@ Size2 PopupPanel::get_minimum_size() const { void PopupPanel::_update_child_rects() { - Ref<StyleBox> p = get_stylebox("panel"); + Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name()); Vector2 cpos(p->get_offset()); Vector2 csize(get_size() - p->get_minimum_size()); @@ -281,24 +185,32 @@ void PopupPanel::_update_child_rects() { if (c->is_set_as_toplevel()) continue; - c->set_position(cpos); - c->set_size(csize); + if (c == panel) { + c->set_position(Vector2()); + c->set_size(get_size()); + } else { + c->set_position(cpos); + c->set_size(csize); + } } } void PopupPanel::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - - get_stylebox("panel")->draw(get_canvas_item(), Rect2(Point2(), get_size())); - } else if (p_what == NOTIFICATION_READY) { + if (p_what == NOTIFICATION_THEME_CHANGED) { + panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name())); + } else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) { + panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name())); _update_child_rects(); - } else if (p_what == NOTIFICATION_RESIZED) { + } else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) { _update_child_rects(); } } PopupPanel::PopupPanel() { + + panel = memnew(Panel); + add_child(panel); } diff --git a/scene/gui/popup.h b/scene/gui/popup.h index ff472170b3..6cd2b4028f 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -31,44 +31,26 @@ #ifndef POPUP_H #define POPUP_H -#include "scene/gui/control.h" +#include "scene/main/window.h" -class Popup : public Control { +class Popup : public Window { - GDCLASS(Popup, Control); + GDCLASS(Popup, Window); - bool exclusive; - bool popped_up; + Window *parent_visible; -private: - void _popup(const Rect2 &p_bounds = Rect2(), const bool p_centered = false); + void _input_from_window(const Ref<InputEvent> &p_event); + void _parent_focused(); protected: - virtual void _post_popup() {} + void _close_pressed(); + virtual Rect2i _popup_adjust_rect() const; - void _gui_input(Ref<InputEvent> p_event); void _notification(int p_what); - virtual void _fix_size(); static void _bind_methods(); public: - enum { - NOTIFICATION_POST_POPUP = 80, - NOTIFICATION_POPUP_HIDE = 81 - }; - - void set_exclusive(bool p_exclusive); - bool is_exclusive() const; - - void popup_centered_ratio(float p_screen_ratio = 0.75); - void popup_centered(const Size2 &p_size = Size2()); - void popup_centered_minsize(const Size2 &p_minsize = Size2()); void set_as_minsize(); - void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75); - virtual void popup(const Rect2 &p_bounds = Rect2()); - - virtual String get_configuration_warning() const; - Popup(); ~Popup(); }; @@ -77,13 +59,16 @@ class PopupPanel : public Popup { GDCLASS(PopupPanel, Popup); + Panel *panel; + protected: void _update_child_rects(); void _notification(int p_what); + virtual Size2 _get_contents_minimum_size() const; + public: void set_child_rect(Control *p_child); - virtual Size2 get_minimum_size() const; PopupPanel(); }; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index e75dadd5e0..c096dc94cb 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -30,11 +30,12 @@ #include "popup_menu.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" #include "core/translation.h" +#include "scene/gui/control.h" String PopupMenu::_get_accel_text(int p_item) const { @@ -47,18 +48,18 @@ String PopupMenu::_get_accel_text(int p_item) const { return String(); } -Size2 PopupMenu::get_minimum_size() const { +Size2 PopupMenu::_get_contents_minimum_size() const { - int vseparation = get_constant("vseparation"); - int hseparation = get_constant("hseparation"); + int vseparation = get_theme_constant("vseparation"); + int hseparation = get_theme_constant("hseparation"); - Size2 minsize = get_stylebox("panel")->get_minimum_size(); - Ref<Font> font = get_font("font"); + Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); + Ref<Font> font = get_theme_font("font"); float max_w = 0; float icon_w = 0; int font_h = font->get_height(); - int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation; + int check_w = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation; int accel_max_w = 0; bool has_check = false; @@ -93,7 +94,7 @@ Size2 PopupMenu::get_minimum_size() const { } if (items[i].submenu != "") - size.width += get_icon("submenu")->get_width(); + size.width += get_theme_icon("submenu")->get_width(); max_w = MAX(max_w, size.width); @@ -112,15 +113,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { if (p_over.x < 0 || p_over.x >= get_size().width) return -1; - Ref<StyleBox> style = get_stylebox("panel"); + Ref<StyleBox> style = get_theme_stylebox("panel"); Point2 ofs = style->get_offset(); if (ofs.y > p_over.y) return -1; - Ref<Font> font = get_font("font"); - int vseparation = get_constant("vseparation"); + Ref<Font> font = get_theme_font("font"); + int vseparation = get_theme_constant("vseparation"); float font_h = font->get_height(); for (int i = 0; i < items.size(); i++) { @@ -152,27 +153,27 @@ void PopupMenu::_activate_submenu(int over) { ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + "."); Popup *pm = Object::cast_to<Popup>(n); ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + "."); - if (pm->is_visible_in_tree()) + if (pm->is_visible()) return; //already visible! - Point2 p = get_global_position(); + Point2 p = get_position(); Rect2 pr(p, get_size()); - Ref<StyleBox> style = get_stylebox("panel"); + Ref<StyleBox> style = get_theme_stylebox("panel"); - Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale(); + Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y); Size2 size = pm->get_size(); // fix pos - if (pos.x + size.width > get_viewport_rect().size.width) + if (pos.x + size.width > get_parent_rect().size.width) pos.x = p.x - size.width; pm->set_position(pos); - pm->set_scale(get_global_transform().get_scale()); + // pm->set_scale(get_global_transform().get_scale()); pm->popup(); PopupMenu *pum = Object::cast_to<PopupMenu>(pm); if (pum) { - pr.position -= pum->get_global_position(); + pr.position -= pum->get_position(); pum->clear_autohide_areas(); pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache)); if (over < items.size() - 1) { @@ -184,6 +185,9 @@ void PopupMenu::_activate_submenu(int over) { void PopupMenu::_submenu_timeout() { + //if (!has_focus()) { + // return; //do not activate if not has focus + //} if (mouse_over == submenu_over) _activate_submenu(mouse_over); @@ -192,20 +196,27 @@ void PopupMenu::_submenu_timeout() { void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { - int vseparation = get_constant("vseparation"); - Ref<Font> font = get_font("font"); + int vseparation = get_theme_constant("vseparation"); + Ref<Font> font = get_theme_font("font"); - float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y; + Rect2 visible_rect = get_usable_parent_rect(); + + int dy = (vseparation + font->get_height()) * 3 * p_factor; if (dy > 0) { - const float global_top = get_global_position().y; - const float limit = global_top < 0 ? -global_top : 0; + const float global_top = get_position().y; + const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0; dy = MIN(dy, limit); } else if (dy < 0) { - const float global_bottom = get_global_position().y + get_size().y * get_global_transform().get_scale().y; - const float viewport_height = get_viewport_rect().size.y; + const float global_bottom = get_position().y + get_size().y; + const float viewport_height = visible_rect.position.y + visible_rect.size.y; const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0; dy = -MIN(-dy, limit); } + + if (dy == 0) { + return; + } + set_position(get_position() + Vector2(0, dy)); Ref<InputEventMouseMotion> ie; @@ -231,8 +242,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal("id_focused", i); - update(); - accept_event(); + control->update(); + set_input_as_handled(); break; } } @@ -251,8 +262,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal("id_focused", i); - update(); - accept_event(); + control->update(); + set_input_as_handled(); break; } } @@ -261,13 +272,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { Node *n = get_parent(); if (n && Object::cast_to<PopupMenu>(n)) { hide(); - accept_event(); + set_input_as_handled(); } } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) { _activate_submenu(mouse_over); - accept_event(); + set_input_as_handled(); } } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { @@ -278,7 +289,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } else { activate_item(mouse_over); } - accept_event(); + set_input_as_handled(); } } @@ -294,15 +305,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { case BUTTON_WHEEL_DOWN: { - if (get_global_position().y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) { - _scroll(-b->get_factor(), b->get_position()); - } + _scroll(-b->get_factor(), b->get_position()); } break; case BUTTON_WHEEL_UP: { - if (get_global_position().y < 0) { - _scroll(b->get_factor(), b->get_position()); - } + _scroll(b->get_factor(), b->get_position()); } break; default: { // Allow activating item by releasing the LMB or any that was down when the popup appeared @@ -338,7 +345,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } } - //update(); + //control->update(); } Ref<InputEventMouseMotion> m = p_event; @@ -354,7 +361,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E->get().has_point(m->get_position())) { - call_deferred("hide"); + + _close_pressed(); return; } } @@ -364,7 +372,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { if (id < 0) { mouse_over = -1; - update(); + control->update(); return; } @@ -375,15 +383,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { if (over != mouse_over) { mouse_over = over; - update(); + control->update(); } } Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { - if (get_global_position().y + get_size().y > get_viewport_rect().size.y || get_global_position().y < 0) { - _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); - } + _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); } Ref<InputEventKey> k = p_event; @@ -416,218 +422,227 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { if (items[i].text.findn(search_string) == 0) { mouse_over = i; emit_signal("id_focused", i); - update(); - accept_event(); + control->update(); + set_input_as_handled(); break; } } } } -bool PopupMenu::has_point(const Point2 &p_point) const { +void PopupMenu::_draw() { - if (parent_rect.has_point(p_point)) - return true; - for (const List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { + RID ci = control->get_canvas_item(); + Size2 size = get_size(); - if (E->get().has_point(p_point)) - return true; - } + Ref<StyleBox> style = get_theme_stylebox("panel"); + Ref<StyleBox> hover = get_theme_stylebox("hover"); + Ref<Font> font = get_theme_font("font"); + // In Item::checkable_type enum order (less the non-checkable member) + Ref<Texture2D> check[] = { get_theme_icon("checked"), get_theme_icon("radio_checked") }; + Ref<Texture2D> uncheck[] = { get_theme_icon("unchecked"), get_theme_icon("radio_unchecked") }; + Ref<Texture2D> submenu = get_theme_icon("submenu"); + Ref<StyleBox> separator = get_theme_stylebox("separator"); + Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left"); + Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right"); - return Control::has_point(p_point); -} - -void PopupMenu::_notification(int p_what) { + style->draw(ci, Rect2(Point2(), get_size())); + Point2 ofs = style->get_offset(); + int vseparation = get_theme_constant("vseparation"); + int hseparation = get_theme_constant("hseparation"); + Color font_color = get_theme_color("font_color"); + Color font_color_disabled = get_theme_color("font_color_disabled"); + Color font_color_accel = get_theme_color("font_color_accel"); + Color font_color_hover = get_theme_color("font_color_hover"); + float font_h = font->get_height(); - switch (p_what) { + // Add the check and the wider icon to the offset of all items. + float icon_ofs = 0.0; + bool has_check = false; + for (int i = 0; i < items.size(); i++) { - case NOTIFICATION_ENTER_TREE: { + if (!items[i].icon.is_null()) + icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs); - PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent()); - if (pm) { - // Inherit submenu's popup delay time from parent menu - float pm_delay = pm->get_submenu_popup_delay(); - set_submenu_popup_delay(pm_delay); - } - } break; - case NOTIFICATION_TRANSLATION_CHANGED: { + if (items[i].checkable_type) + has_check = true; + } + if (icon_ofs > 0.0) + icon_ofs += hseparation; - for (int i = 0; i < items.size(); i++) { - items.write[i].xl_text = tr(items[i].text); - } + float check_ofs = 0.0; + if (has_check) + check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation; - minimum_size_changed(); - update(); - } break; - case NOTIFICATION_DRAW: { - - RID ci = get_canvas_item(); - Size2 size = get_size(); - - Ref<StyleBox> style = get_stylebox("panel"); - Ref<StyleBox> hover = get_stylebox("hover"); - Ref<Font> font = get_font("font"); - // In Item::checkable_type enum order (less the non-checkable member) - Ref<Texture2D> check[] = { get_icon("checked"), get_icon("radio_checked") }; - Ref<Texture2D> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") }; - Ref<Texture2D> submenu = get_icon("submenu"); - Ref<StyleBox> separator = get_stylebox("separator"); - Ref<StyleBox> labeled_separator_left = get_stylebox("labeled_separator_left"); - Ref<StyleBox> labeled_separator_right = get_stylebox("labeled_separator_right"); - - style->draw(ci, Rect2(Point2(), get_size())); - Point2 ofs = style->get_offset(); - int vseparation = get_constant("vseparation"); - int hseparation = get_constant("hseparation"); - Color font_color = get_color("font_color"); - Color font_color_disabled = get_color("font_color_disabled"); - Color font_color_accel = get_color("font_color_accel"); - Color font_color_hover = get_color("font_color_hover"); - float font_h = font->get_height(); - - // Add the check and the wider icon to the offset of all items. - float icon_ofs = 0.0; - bool has_check = false; - for (int i = 0; i < items.size(); i++) { + for (int i = 0; i < items.size(); i++) { - if (!items[i].icon.is_null()) - icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs); + if (i > 0) + ofs.y += vseparation; + Point2 item_ofs = ofs; + Size2 icon_size; + float h; - if (items[i].checkable_type) - has_check = true; - } - if (icon_ofs > 0.0) - icon_ofs += hseparation; + if (!items[i].icon.is_null()) { - float check_ofs = 0.0; - if (has_check) - check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation; + icon_size = items[i].icon->get_size(); + h = MAX(icon_size.height, font_h); + } else { - for (int i = 0; i < items.size(); i++) { + h = font_h; + } - if (i > 0) - ofs.y += vseparation; - Point2 item_ofs = ofs; - Size2 icon_size; - float h; + if (i == mouse_over) { - if (!items[i].icon.is_null()) { + hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation))); + } - icon_size = items[i].icon->get_size(); - h = MAX(icon_size.height, font_h); - } else { + String text = items[i].xl_text; - h = font_h; + item_ofs.x += items[i].h_ofs; + if (items[i].separator) { + + int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; + if (text != String()) { + int ss = font->get_string_size(text).width; + int center = (get_size().width) / 2; + int l = center - ss / 2; + int r = center + ss / 2; + if (l > item_ofs.x) { + labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h))); } - - if (i == mouse_over) { - - hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation))); + if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) { + labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h))); } + } else { + separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h))); + } + } - String text = items[i].xl_text; + Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); - item_ofs.x += items[i].h_ofs; - if (items[i].separator) { + if (items[i].checkable_type) { + Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); + icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color); + } - int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; - if (text != String()) { - int ss = font->get_string_size(text).width; - int center = (get_size().width) / 2; - int l = center - ss / 2; - int r = center + ss / 2; - if (l > item_ofs.x) { - labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h))); - } - if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) { - labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h))); - } - } else { - separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h))); - } - } + if (!items[i].icon.is_null()) { + items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + } - Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + if (items[i].submenu != "") { + submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); + } - if (items[i].checkable_type) { - Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); - icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color); - } + item_ofs.y += font->get_ascent(); + if (items[i].separator) { - if (!items[i].icon.is_null()) { - items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); - } + if (text != String()) { + int center = (get_size().width - font->get_string_size(text).width) / 2; + font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled); + } + } else { - if (items[i].submenu != "") { - submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); - } + item_ofs.x += icon_ofs + check_ofs; + font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); + } - item_ofs.y += font->get_ascent(); - if (items[i].separator) { + if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { + //accelerator + String text2 = _get_accel_text(i); + item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width; + font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel); + } - if (text != String()) { - int center = (get_size().width - font->get_string_size(text).width) / 2; - font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled); - } - } else { + items.write[i]._ofs_cache = ofs.y; - item_ofs.x += icon_ofs + check_ofs; - font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); - } + ofs.y += h; + } +} - if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { - //accelerator - String text2 = _get_accel_text(i); - item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width; - font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel); - } +void PopupMenu::_notification(int p_what) { + + switch (p_what) { - items.write[i]._ofs_cache = ofs.y; + case NOTIFICATION_ENTER_TREE: { - ofs.y += h; + PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent()); + if (pm) { + // Inherit submenu's popup delay time from parent menu + float pm_delay = pm->get_submenu_popup_delay(); + set_submenu_popup_delay(pm_delay); } } break; - case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_TRANSLATION_CHANGED: { - if (hide_on_window_lose_focus) - hide(); + for (int i = 0; i < items.size(); i++) { + items.write[i].xl_text = tr(items[i].text); + } + + child_controls_changed(); + control->update(); } break; - case NOTIFICATION_MOUSE_ENTER: { + case NOTIFICATION_WM_MOUSE_ENTER: { - grab_focus(); + //grab_focus(); } break; - case NOTIFICATION_MOUSE_EXIT: { + case NOTIFICATION_WM_MOUSE_EXIT: { if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) { mouse_over = -1; - update(); + control->update(); } } break; case NOTIFICATION_POST_POPUP: { - initial_button_mask = Input::get_singleton()->get_mouse_button_mask(); + initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask(); during_grabbed_click = (bool)initial_button_mask; } break; - case NOTIFICATION_POPUP_HIDE: { + case NOTIFICATION_WM_SIZE_CHANGED: { - if (mouse_over >= 0) { - mouse_over = -1; - update(); + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + //only used when using operating system windows + if (get_window_id() != DisplayServer::INVALID_WINDOW_ID && autohide_areas.size()) { + Point2 mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); + mouse_pos -= get_position(); + + for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { + + if (!Rect2(Point2(), get_size()).has_point(mouse_pos) && E->get().has_point(mouse_pos)) { + _close_pressed(); + return; + } + } } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { - for (int i = 0; i < items.size(); i++) { - if (items[i].submenu == "") - continue; + if (!is_visible()) { + if (mouse_over >= 0) { + mouse_over = -1; + control->update(); + } + + for (int i = 0; i < items.size(); i++) { + if (items[i].submenu == "") + continue; - Node *n = get_node(items[i].submenu); - if (!n) - continue; + Node *n = get_node(items[i].submenu); + if (!n) + continue; - PopupMenu *pm = Object::cast_to<PopupMenu>(n); - if (!pm || !pm->is_visible()) - continue; + PopupMenu *pm = Object::cast_to<PopupMenu>(n); + if (!pm || !pm->is_visible()) + continue; - pm->hide(); + pm->hide(); + } + + set_process_internal(false); + } else { + if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + set_process_internal(true); + } } } break; } @@ -648,8 +663,8 @@ void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { @@ -658,8 +673,8 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.icon = p_icon; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) { @@ -668,8 +683,8 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { @@ -679,8 +694,8 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String & item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) { @@ -689,8 +704,8 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { @@ -700,8 +715,8 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) { @@ -711,8 +726,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int item.max_states = p_max_states; item.state = p_default_state; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } #define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \ @@ -729,8 +744,8 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_g Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { @@ -739,8 +754,8 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortC ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.icon = p_icon; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { @@ -749,8 +764,8 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { @@ -760,8 +775,8 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref< item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { @@ -770,8 +785,8 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { @@ -781,8 +796,8 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) { @@ -793,8 +808,8 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, item.id = p_id == -1 ? items.size() : p_id; item.submenu = p_submenu; items.push_back(item); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } #undef ITEM_SETUP_WITH_ACCEL @@ -808,16 +823,16 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { items.write[p_idx].text = p_text; items.write[p_idx].xl_text = tr(p_text); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon = p_icon; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_checked(int p_idx, bool p_checked) { @@ -825,16 +840,16 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { items.write[p_idx].checked = p_checked; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_id(int p_idx, int p_id) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].id = p_id; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { @@ -842,40 +857,40 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].accel = p_accel; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].metadata = p_meta; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].disabled = p_disabled; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].submenu = p_submenu; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::toggle_item_checked(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checked = !items[p_idx].checked; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } String PopupMenu::get_item_text(int p_idx) const { @@ -968,7 +983,7 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].separator = p_separator; - update(); + control->update(); } bool PopupMenu::is_item_separator(int p_idx) const { @@ -980,21 +995,21 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; - update(); + control->update(); } void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; - update(); + control->update(); } void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].tooltip = p_tooltip; - update(); + control->update(); } void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global) { @@ -1009,29 +1024,29 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo _ref_shortcut(items[p_idx].shortcut); } - update(); + control->update(); } void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].h_ofs = p_offset; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::set_item_multistate(int p_idx, int p_state) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].state = p_state; - update(); + control->update(); } void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].shortcut_is_disabled = p_disabled; - update(); + control->update(); } void PopupMenu::toggle_item_multistate(int p_idx) { @@ -1045,7 +1060,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) { if (items.write[p_idx].max_states <= items[p_idx].state) items.write[p_idx].state = 0; - update(); + control->update(); } bool PopupMenu::is_item_checkable(int p_idx) const { @@ -1177,8 +1192,8 @@ void PopupMenu::remove_item(int p_idx) { } items.remove(p_idx); - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } void PopupMenu::add_separator(const String &p_text) { @@ -1191,7 +1206,7 @@ void PopupMenu::add_separator(const String &p_text) { sep.xl_text = tr(p_text); } items.push_back(sep); - update(); + control->update(); } void PopupMenu::clear() { @@ -1203,8 +1218,8 @@ void PopupMenu::clear() { } items.clear(); mouse_over = -1; - update(); - minimum_size_changed(); + control->update(); + child_controls_changed(); } Array PopupMenu::_get_items() const { @@ -1345,16 +1360,6 @@ bool PopupMenu::get_allow_search() const { return allow_search; } -void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) { - - hide_on_window_lose_focus = p_enabled; -} - -bool PopupMenu::is_hide_on_window_lose_focus() const { - - return hide_on_window_lose_focus; -} - String PopupMenu::get_tooltip(const Point2 &p_pos) const { int over = _get_mouse_over(p_pos); @@ -1387,6 +1392,14 @@ void PopupMenu::clear_autohide_areas() { autohide_areas.clear(); } +void PopupMenu::take_mouse_focus() { + ERR_FAIL_COND(!is_inside_tree()); + + if (get_parent()) { + get_parent()->get_viewport()->pass_mouse_focus_to(this, control); + } +} + void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input); @@ -1466,9 +1479,6 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_submenu_popup_delay", "seconds"), &PopupMenu::set_submenu_popup_delay); ClassDB::bind_method(D_METHOD("get_submenu_popup_delay"), &PopupMenu::get_submenu_popup_delay); - ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus); - ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus); - ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search); ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search); @@ -1486,7 +1496,6 @@ void PopupMenu::_bind_methods() { void PopupMenu::popup(const Rect2 &p_bounds) { - grab_click_focus(); moved = Vector2(); invalidated_click = true; Popup::popup(p_bounds); @@ -1494,6 +1503,13 @@ void PopupMenu::popup(const Rect2 &p_bounds) { PopupMenu::PopupMenu() { + control = memnew(Control); + add_child(control); + + control->set_anchors_and_margins_preset(Control::PRESET_WIDE); + connect("window_input", callable_mp(this, &PopupMenu::_gui_input)); + control->connect("draw", callable_mp(this, &PopupMenu::_draw)); + mouse_over = -1; submenu_over = -1; initial_button_mask = 0; @@ -1503,12 +1519,9 @@ PopupMenu::PopupMenu() { search_time_msec = 0; search_string = ""; - set_focus_mode(FOCUS_ALL); - set_as_toplevel(true); set_hide_on_item_selection(true); set_hide_on_checkable_item_selection(true); set_hide_on_multistate_item_selection(false); - set_hide_on_window_lose_focus(true); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index a3a858cfde..2eef1f009d 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -32,6 +32,7 @@ #define POPUP_MENU_H #include "scene/gui/popup.h" +#include "scene/gui/shortcut.h" class PopupMenu : public Popup { @@ -87,7 +88,7 @@ class PopupMenu : public Popup { Rect2 parent_rect; String _get_accel_text(int p_item) const; int _get_mouse_over(const Point2 &p_over) const; - virtual Size2 get_minimum_size() const; + virtual Size2 _get_contents_minimum_size() const; void _scroll(float p_factor, const Point2 &p_over); void _gui_input(const Ref<InputEvent> &p_event); void _activate_submenu(int over); @@ -97,7 +98,6 @@ class PopupMenu : public Popup { bool hide_on_item_selection; bool hide_on_checkable_item_selection; bool hide_on_multistate_item_selection; - bool hide_on_window_lose_focus; Vector2 moved; Array _get_items() const; @@ -112,9 +112,11 @@ class PopupMenu : public Popup { uint64_t search_time_msec; String search_string; -protected: - virtual bool has_point(const Point2 &p_point) const; + Control *control; + + void _draw(); +protected: friend class MenuButton; void _notification(int p_what); static void _bind_methods(); @@ -213,8 +215,7 @@ public: virtual void popup(const Rect2 &p_bounds = Rect2()); - void set_hide_on_window_lose_focus(bool p_enabled); - bool is_hide_on_window_lose_focus() const; + void take_mouse_focus(); PopupMenu(); ~PopupMenu(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index e11295d7e7..362c45453d 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -32,9 +32,9 @@ Size2 ProgressBar::get_minimum_size() const { - Ref<StyleBox> bg = get_stylebox("bg"); - Ref<StyleBox> fg = get_stylebox("fg"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); + Ref<StyleBox> fg = get_theme_stylebox("fg"); + Ref<Font> font = get_theme_font("font"); Size2 minimum_size = bg->get_minimum_size(); minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height); @@ -52,10 +52,10 @@ void ProgressBar::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> bg = get_stylebox("bg"); - Ref<StyleBox> fg = get_stylebox("fg"); - Ref<Font> font = get_font("font"); - Color font_color = get_color("font_color"); + Ref<StyleBox> bg = get_theme_stylebox("bg"); + Ref<StyleBox> fg = get_theme_stylebox("fg"); + Ref<Font> font = get_theme_font("font"); + Color font_color = get_theme_color("font_color"); draw_style_box(bg, Rect2(Point2(), get_size())); float r = get_as_ratio(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index e4651ef473..df28a4c12f 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -34,6 +34,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "scene/scene_string_names.h" +#include "servers/display_server.h" #include "modules/modules_enabled.gen.h" #ifdef MODULE_REGEX_ENABLED @@ -142,7 +143,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) { } Rect2 RichTextLabel::_get_text_rect() { - Ref<StyleBox> style = get_stylebox("normal"); + Ref<StyleBox> style = get_theme_stylebox("normal"); return Rect2(style->get_offset(), get_size() - style->get_minimum_size()); } @@ -240,7 +241,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & l.space_caches.push_back(spaces); \ } \ line_wrapped = false; \ - y += line_height + get_constant(SceneStringNames::get_singleton()->line_separation); \ + y += line_height + get_theme_constant(SceneStringNames::get_singleton()->line_separation); \ line_height = 0; \ line_ascent = 0; \ line_descent = 0; \ @@ -305,8 +306,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Color selection_bg; if (p_mode == PROCESS_DRAW) { - selection_fg = get_color("font_color_selected"); - selection_bg = get_color("selection_color"); + selection_fg = get_theme_color("font_color_selected"); + selection_bg = get_theme_color("selection_color"); } int rchar = 0; @@ -667,13 +668,13 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & lh = 0; ItemTable *table = static_cast<ItemTable *>(it); - int hseparation = get_constant("table_hseparation"); - int vseparation = get_constant("table_vseparation"); + int hseparation = get_theme_constant("table_hseparation"); + int vseparation = get_theme_constant("table_vseparation"); Color ccolor = _find_color(table, p_base_color); Vector2 draw_ofs = Point2(wofs, y); - Color font_color_shadow = get_color("font_color_shadow"); - bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs2(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + Color font_color_shadow = get_theme_color("font_color_shadow"); + bool use_outline = get_theme_constant("shadow_as_outline"); + Point2 shadow_ofs2(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); if (p_mode == PROCESS_CACHE) { @@ -987,11 +988,11 @@ void RichTextLabel::_notification(int p_what) { Size2 size = get_size(); Rect2 text_rect = _get_text_rect(); - draw_style_box(get_stylebox("normal"), Rect2(Point2(), size)); + draw_style_box(get_theme_stylebox("normal"), Rect2(Point2(), size)); if (has_focus()) { VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, true); - draw_style_box(get_stylebox("focus"), Rect2(Point2(), size)); + draw_style_box(get_theme_stylebox("focus"), Rect2(Point2(), size)); VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); } @@ -1012,11 +1013,11 @@ void RichTextLabel::_notification(int p_what) { if (from_line >= main->lines.size()) break; //nothing to draw int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs; - Ref<Font> base_font = get_font("normal_font"); - Color base_color = get_color("default_color"); - Color font_color_shadow = get_color("font_color_shadow"); - bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + Ref<Font> base_font = get_theme_font("normal_font"); + Color base_color = get_theme_color("default_color"); + Color font_color_shadow = get_theme_color("font_color_shadow"); + bool use_outline = get_theme_constant("shadow_as_outline"); + Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); visible_line_count = 0; while (y < size.height && from_line < main->lines.size()) { @@ -1043,9 +1044,9 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Rect2 text_rect = _get_text_rect(); int ofs = vscroll->get_value(); - Color font_color_shadow = get_color("font_color_shadow"); - bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + Color font_color_shadow = get_theme_color("font_color_shadow"); + bool use_outline = get_theme_constant("shadow_as_outline"); + Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); //todo, change to binary search int from_line = 0; @@ -1061,8 +1062,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item return; int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs; - Ref<Font> base_font = get_font("normal_font"); - Color base_color = get_color("default_color"); + Ref<Font> base_font = get_theme_font("normal_font"); + Color base_color = get_theme_color("default_color"); while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) { @@ -1227,14 +1228,14 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { case KEY_UP: { if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() - get_font("normal_font")->get_height()); + vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height()); handled = true; } } break; case KEY_DOWN: { if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() + get_font("normal_font")->get_height()); + vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height()); handled = true; } } break; @@ -1525,11 +1526,11 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { size.width = fixed_width; } Rect2 text_rect = _get_text_rect(); - Color font_color_shadow = get_color("font_color_shadow"); - bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + Color font_color_shadow = get_theme_color("font_color_shadow"); + bool use_outline = get_theme_constant("shadow_as_outline"); + Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); - Ref<Font> base_font = get_font("normal_font"); + Ref<Font> base_font = get_theme_font("normal_font"); for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) { @@ -1544,7 +1545,7 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { int total_height = 0; if (p_frame->lines.size()) - total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height; + total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height; main->first_invalid_line = p_frame->lines.size(); @@ -1646,6 +1647,10 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) p_item->line = current_frame->lines.size() - 1; _invalidate_current_line(current_frame); + + if (fixed_width != -1) { + minimum_size_changed(); + } } void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_subitem_line) { @@ -1758,35 +1763,35 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) { } void RichTextLabel::push_normal() { - Ref<Font> normal_font = get_font("normal_font"); + Ref<Font> normal_font = get_theme_font("normal_font"); ERR_FAIL_COND(normal_font.is_null()); push_font(normal_font); } void RichTextLabel::push_bold() { - Ref<Font> bold_font = get_font("bold_font"); + Ref<Font> bold_font = get_theme_font("bold_font"); ERR_FAIL_COND(bold_font.is_null()); push_font(bold_font); } void RichTextLabel::push_bold_italics() { - Ref<Font> bold_italics_font = get_font("bold_italics_font"); + Ref<Font> bold_italics_font = get_theme_font("bold_italics_font"); ERR_FAIL_COND(bold_italics_font.is_null()); push_font(bold_italics_font); } void RichTextLabel::push_italics() { - Ref<Font> italics_font = get_font("italics_font"); + Ref<Font> italics_font = get_theme_font("italics_font"); ERR_FAIL_COND(italics_font.is_null()); push_font(italics_font); } void RichTextLabel::push_mono() { - Ref<Font> mono_font = get_font("mono_font"); + Ref<Font> mono_font = get_theme_font("mono_font"); ERR_FAIL_COND(mono_font.is_null()); push_font(mono_font); @@ -1967,6 +1972,10 @@ void RichTextLabel::clear() { selection.click = NULL; selection.active = false; current_idx = 1; + + if (fixed_width != -1) { + minimum_size_changed(); + } } void RichTextLabel::set_tab_size(int p_spaces) { @@ -2044,13 +2053,13 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { int pos = 0; List<String> tag_stack; - Ref<Font> normal_font = get_font("normal_font"); - Ref<Font> bold_font = get_font("bold_font"); - Ref<Font> italics_font = get_font("italics_font"); - Ref<Font> bold_italics_font = get_font("bold_italics_font"); - Ref<Font> mono_font = get_font("mono_font"); + Ref<Font> normal_font = get_theme_font("normal_font"); + Ref<Font> bold_font = get_theme_font("bold_font"); + Ref<Font> italics_font = get_theme_font("italics_font"); + Ref<Font> bold_italics_font = get_theme_font("bold_italics_font"); + Ref<Font> mono_font = get_theme_font("mono_font"); - Color base_color = get_color("default_color"); + Color base_color = get_theme_color("default_color"); int indent_level = 0; @@ -2518,7 +2527,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p _validate_line_caches(main); - int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_font("normal_font")->get_height(); + int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_theme_font("normal_font")->get_height(); float offset = 0; @@ -2584,7 +2593,7 @@ void RichTextLabel::selection_copy() { } if (text != "") { - OS::get_singleton()->set_clipboard(text); + DisplayServer::get_singleton()->clipboard_set(text); } } @@ -2692,7 +2701,7 @@ void RichTextLabel::install_effect(const Variant effect) { int RichTextLabel::get_content_height() { int total_height = 0; if (main->lines.size()) - total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height; + total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height; return total_height; } diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index fef5e00984..5e9541730e 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -33,6 +33,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" +#include "scene/main/window.h" bool ScrollBar::focus_by_default = false; @@ -71,8 +72,8 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (b->is_pressed()) { double ofs = orientation == VERTICAL ? b->get_position().y : b->get_position().x; - Ref<Texture2D> decr = get_icon("decrement"); - Ref<Texture2D> incr = get_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width(); @@ -148,7 +149,7 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (drag.active) { double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x; - Ref<Texture2D> decr = get_icon("decrement"); + Ref<Texture2D> decr = get_theme_icon("decrement"); double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); ofs -= decr_size; @@ -159,8 +160,8 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { } else { double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x; - Ref<Texture2D> decr = get_icon("decrement"); - Ref<Texture2D> incr = get_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width(); @@ -233,17 +234,17 @@ void ScrollBar::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<Texture2D> decr = highlight == HIGHLIGHT_DECR ? get_icon("decrement_highlight") : get_icon("decrement"); - Ref<Texture2D> incr = highlight == HIGHLIGHT_INCR ? get_icon("increment_highlight") : get_icon("increment"); - Ref<StyleBox> bg = has_focus() ? get_stylebox("scroll_focus") : get_stylebox("scroll"); + Ref<Texture2D> decr = highlight == HIGHLIGHT_DECR ? get_theme_icon("decrement_highlight") : get_theme_icon("decrement"); + Ref<Texture2D> incr = highlight == HIGHLIGHT_INCR ? get_theme_icon("increment_highlight") : get_theme_icon("increment"); + Ref<StyleBox> bg = has_focus() ? get_theme_stylebox("scroll_focus") : get_theme_stylebox("scroll"); Ref<StyleBox> grabber; if (drag.active) - grabber = get_stylebox("grabber_pressed"); + grabber = get_theme_stylebox("grabber_pressed"); else if (highlight == HIGHLIGHT_RANGE) - grabber = get_stylebox("grabber_highlight"); + grabber = get_theme_stylebox("grabber_highlight"); else - grabber = get_stylebox("grabber"); + grabber = get_theme_stylebox("grabber"); Point2 ofs; @@ -416,7 +417,7 @@ void ScrollBar::_notification(int p_what) { double ScrollBar::get_grabber_min_size() const { - Ref<StyleBox> grabber = get_stylebox("grabber"); + Ref<StyleBox> grabber = get_theme_stylebox("grabber"); Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size(); return (orientation == VERTICAL) ? gminsize.height : gminsize.width; } @@ -442,17 +443,17 @@ double ScrollBar::get_area_size() const { switch (orientation) { case VERTICAL: { double area = get_size().height; - area -= get_stylebox("scroll")->get_minimum_size().height; - area -= get_icon("increment")->get_height(); - area -= get_icon("decrement")->get_height(); + area -= get_theme_stylebox("scroll")->get_minimum_size().height; + area -= get_theme_icon("increment")->get_height(); + area -= get_theme_icon("decrement")->get_height(); area -= get_grabber_min_size(); return area; } break; case HORIZONTAL: { double area = get_size().width; - area -= get_stylebox("scroll")->get_minimum_size().width; - area -= get_icon("increment")->get_width(); - area -= get_icon("decrement")->get_width(); + area -= get_theme_stylebox("scroll")->get_minimum_size().width; + area -= get_theme_icon("increment")->get_width(); + area -= get_theme_icon("decrement")->get_width(); area -= get_grabber_min_size(); return area; } break; @@ -468,14 +469,14 @@ double ScrollBar::get_area_offset() const { if (orientation == VERTICAL) { - ofs += get_stylebox("hscroll")->get_margin(MARGIN_TOP); - ofs += get_icon("decrement")->get_height(); + ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_TOP); + ofs += get_theme_icon("decrement")->get_height(); } if (orientation == HORIZONTAL) { - ofs += get_stylebox("hscroll")->get_margin(MARGIN_LEFT); - ofs += get_icon("decrement")->get_width(); + ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_LEFT); + ofs += get_theme_icon("decrement")->get_width(); } return ofs; @@ -500,9 +501,9 @@ double ScrollBar::get_grabber_offset() const { Size2 ScrollBar::get_minimum_size() const { - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); - Ref<StyleBox> bg = get_stylebox("scroll"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); + Ref<StyleBox> bg = get_theme_stylebox("scroll"); Size2 minsize; if (orientation == VERTICAL) { @@ -559,8 +560,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) { drag_node_accum = Vector2(); last_drag_node_accum = Vector2(); drag_node_from = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); - - drag_node_touching = OS::get_singleton()->has_touchscreen_ui_hint(); + drag_node_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); drag_node_touching_deaccel = false; time_since_motion = 0; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index c25a6d5a0c..fb17adf96e 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -30,7 +30,7 @@ #include "scroll_container.h" #include "core/os/os.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" bool ScrollContainer::clips_input() const { @@ -39,7 +39,7 @@ bool ScrollContainer::clips_input() const { Size2 ScrollContainer::get_minimum_size() const { - Ref<StyleBox> sb = get_stylebox("bg"); + Ref<StyleBox> sb = get_theme_stylebox("bg"); Size2 min_size; for (int i = 0; i < get_child_count(); i++) { @@ -129,7 +129,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) accept_event(); //accept event if scroll changed - if (!OS::get_singleton()->has_touchscreen_ui_hint()) + if (!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()))) return; if (mb->get_button_index() != BUTTON_LEFT) @@ -145,7 +145,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { drag_accum = Vector2(); last_drag_accum = Vector2(); drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value()); - drag_touching = OS::get_singleton()->has_touchscreen_ui_hint(); + drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); drag_touching_deaccel = false; beyond_deadzone = false; time_since_motion = 0; @@ -276,7 +276,7 @@ void ScrollContainer::_notification(int p_what) { Size2 size = get_size(); Point2 ofs; - Ref<StyleBox> sb = get_stylebox("bg"); + Ref<StyleBox> sb = get_theme_stylebox("bg"); size -= sb->get_minimum_size(); ofs += sb->get_offset(); @@ -323,7 +323,7 @@ void ScrollContainer::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> sb = get_stylebox("bg"); + Ref<StyleBox> sb = get_theme_stylebox("bg"); draw_style_box(sb, Rect2(Vector2(), get_size())); update_scrollbars(); @@ -404,7 +404,7 @@ void ScrollContainer::_notification(int p_what) { void ScrollContainer::update_scrollbars() { Size2 size = get_size(); - Ref<StyleBox> sb = get_stylebox("bg"); + Ref<StyleBox> sb = get_theme_stylebox("bg"); size -= sb->get_minimum_size(); Size2 hmin; diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index 4635efb233..75c4b7cce9 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -34,9 +34,9 @@ Size2 Separator::get_minimum_size() const { Size2 ms(3, 3); if (orientation == VERTICAL) { - ms.x = get_constant("separation"); + ms.x = get_theme_constant("separation"); } else { // HORIZONTAL - ms.y = get_constant("separation"); + ms.y = get_theme_constant("separation"); } return ms; } @@ -48,7 +48,7 @@ void Separator::_notification(int p_what) { case NOTIFICATION_DRAW: { Size2i size = get_size(); - Ref<StyleBox> style = get_stylebox("separator"); + Ref<StyleBox> style = get_theme_stylebox("separator"); Size2i ssize = style->get_minimum_size() + style->get_center_size(); if (orientation == VERTICAL) { diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h index 59d3245db5..b22c3441c5 100644 --- a/scene/gui/shortcut.h +++ b/scene/gui/shortcut.h @@ -31,7 +31,7 @@ #ifndef SHORTCUT_H #define SHORTCUT_H -#include "core/os/input_event.h" +#include "core/input/input_event.h" #include "core/resource.h" class ShortCut : public Resource { diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 85887ef7b1..e47e2b869d 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -33,10 +33,10 @@ Size2 Slider::get_minimum_size() const { - Ref<StyleBox> style = get_stylebox("slider"); + Ref<StyleBox> style = get_theme_stylebox("slider"); Size2i ss = style->get_minimum_size() + style->get_center_size(); - Ref<Texture2D> grabber = get_icon("grabber"); + Ref<Texture2D> grabber = get_theme_icon("grabber"); Size2i rs = grabber->get_size(); if (orientation == HORIZONTAL) @@ -57,7 +57,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { - Ref<Texture2D> grabber = get_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber"); + Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber"); grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x; double grab_width = (double)grabber->get_size().width; @@ -87,7 +87,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { if (grab.active) { Size2i size = get_size(); - Ref<Texture2D> grabber = get_icon("grabber"); + Ref<Texture2D> grabber = get_theme_icon("grabber"); float motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos; if (orientation == VERTICAL) motion = -motion; @@ -165,10 +165,10 @@ void Slider::_notification(int p_what) { case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2i size = get_size(); - Ref<StyleBox> style = get_stylebox("slider"); - Ref<StyleBox> grabber_area = get_stylebox("grabber_area"); - Ref<Texture2D> grabber = get_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled"); - Ref<Texture2D> tick = get_icon("tick"); + Ref<StyleBox> style = get_theme_stylebox("slider"); + Ref<StyleBox> grabber_area = get_theme_stylebox("grabber_area"); + Ref<Texture2D> grabber = get_theme_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled"); + Ref<Texture2D> tick = get_theme_icon("tick"); double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio(); if (orientation == VERTICAL) { diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 576de98a4f..ccfa8ebf63 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -29,8 +29,9 @@ /*************************************************************************/ #include "spin_box.h" + +#include "core/input/input_filter.h" #include "core/math/expression.h" -#include "core/os/input.h" Size2 SpinBox::get_minimum_size() const { @@ -76,7 +77,7 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) { void SpinBox::_range_click_timeout() { - if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (!drag.enabled && InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { bool up = get_local_mouse_position().y < (get_size().height / 2); set_value(get_value() + (up ? get_step() : -get_step())); @@ -148,7 +149,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { if (drag.enabled) { drag.enabled = false; - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE); warp_mouse(drag.capture_pos); } drag.allowed = false; @@ -165,7 +166,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { set_value(CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max())); } else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) { - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_CAPTURED); drag.enabled = true; drag.base_val = get_value(); drag.diff_y = 0; @@ -195,7 +196,7 @@ void SpinBox::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { - Ref<Texture2D> updown = get_icon("updown"); + Ref<Texture2D> updown = get_theme_icon("updown"); _adjust_width_for_icon(updown); @@ -209,7 +210,7 @@ void SpinBox::_notification(int p_what) { //_value_changed(0); } else if (p_what == NOTIFICATION_ENTER_TREE) { - _adjust_width_for_icon(get_icon("updown")); + _adjust_width_for_icon(get_theme_icon("updown")); _value_changed(0); } else if (p_what == NOTIFICATION_THEME_CHANGED) { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 255278be2b..4eb614a9ac 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -74,8 +74,8 @@ void SplitContainer::_resort() { bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND; // Determine the separation between items - Ref<Texture2D> g = get_icon("grabber"); - int sep = get_constant("separation"); + Ref<Texture2D> g = get_theme_icon("grabber"); + int sep = get_theme_constant("separation"); sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0; // Compute the minimum size @@ -123,8 +123,8 @@ Size2 SplitContainer::get_minimum_size() const { /* Calculate MINIMUM SIZE */ Size2i minimum; - Ref<Texture2D> g = get_icon("grabber"); - int sep = get_constant("separation"); + Ref<Texture2D> g = get_theme_icon("grabber"); + int sep = get_theme_constant("separation"); sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0; for (int i = 0; i < 2; i++) { @@ -167,7 +167,7 @@ void SplitContainer::_notification(int p_what) { case NOTIFICATION_MOUSE_EXIT: { mouse_inside = false; - if (get_constant("autohide")) + if (get_theme_constant("autohide")) update(); } break; case NOTIFICATION_DRAW: { @@ -175,14 +175,14 @@ void SplitContainer::_notification(int p_what) { if (!_getch(0) || !_getch(1)) return; - if (collapsed || (!dragging && !mouse_inside && get_constant("autohide"))) + if (collapsed || (!dragging && !mouse_inside && get_theme_constant("autohide"))) return; if (dragger_visibility != DRAGGER_VISIBLE) return; - int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0; - Ref<Texture2D> tex = get_icon("grabber"); + int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant("separation") : 0; + Ref<Texture2D> tex = get_theme_icon("grabber"); Size2 size = get_size(); if (vertical) @@ -210,7 +210,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { if (mb->is_pressed()) { - int sep = get_constant("separation"); + int sep = get_theme_constant("separation"); if (vertical) { @@ -242,14 +242,14 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { bool mouse_inside_state = false; if (vertical) - mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_constant("separation"); + mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_theme_constant("separation"); else - mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_constant("separation"); + mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant("separation"); if (mouse_inside != mouse_inside_state) { mouse_inside = mouse_inside_state; - if (get_constant("autohide")) + if (get_theme_constant("autohide")) update(); } @@ -270,7 +270,7 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { - int sep = get_constant("separation"); + int sep = get_theme_constant("separation"); if (vertical) { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 6290d364fc..7cecbf7fa2 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -41,14 +41,14 @@ int TabContainer::_get_top_margin() const { return 0; // Respect the minimum tab height. - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); int tab_height = MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height); // Font height or higher icon wins. - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); int content_height = font->get_height(); Vector<Control *> tabs = _get_tabs(); @@ -81,15 +81,15 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { return; // Handle menu button. - Ref<Texture2D> menu = get_icon("menu"); + Ref<Texture2D> menu = get_theme_icon("menu"); if (popup && pos.x > size.width - menu->get_width()) { emit_signal("pre_popup_pressed"); - Vector2 popup_pos = get_global_position(); - popup_pos.x += size.width * get_global_transform().get_scale().x - popup->get_size().width * popup->get_global_transform().get_scale().x; - popup_pos.y += menu->get_height() * get_global_transform().get_scale().y; + Vector2 popup_pos = get_screen_position(); + popup_pos.x += size.width - popup->get_size().width; + popup_pos.y += menu->get_height(); - popup->set_global_position(popup_pos); + popup->set_position(popup_pos); popup->popup(); return; } @@ -107,8 +107,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { popup_ofs = menu->get_width(); } - Ref<Texture2D> increment = get_icon("increment"); - Ref<Texture2D> decrement = get_icon("decrement"); + Ref<Texture2D> increment = get_theme_icon("increment"); + Ref<Texture2D> decrement = get_theme_icon("decrement"); if (pos.x > size.width - increment->get_width() - popup_ofs) { if (last_tab_cache < tabs.size() - 1) { first_tab_cache += 1; @@ -159,7 +159,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { return; } - Ref<Texture2D> menu = get_icon("menu"); + Ref<Texture2D> menu = get_theme_icon("menu"); if (popup) { if (pos.x >= size.width - menu->get_width()) { @@ -191,8 +191,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { popup_ofs = menu->get_width(); } - Ref<Texture2D> increment = get_icon("increment"); - Ref<Texture2D> decrement = get_icon("decrement"); + Ref<Texture2D> increment = get_theme_icon("increment"); + Ref<Texture2D> decrement = get_theme_icon("decrement"); if (pos.x >= size.width - increment->get_width() - popup_ofs) { if (highlight_arrow != 1) { @@ -224,10 +224,10 @@ void TabContainer::_notification(int p_what) { case NOTIFICATION_RESIZED: { Vector<Control *> tabs = _get_tabs(); - int side_margin = get_constant("side_margin"); - Ref<Texture2D> menu = get_icon("menu"); - Ref<Texture2D> increment = get_icon("increment"); - Ref<Texture2D> decrement = get_icon("decrement"); + int side_margin = get_theme_constant("side_margin"); + Ref<Texture2D> menu = get_theme_icon("menu"); + Ref<Texture2D> increment = get_theme_icon("increment"); + Ref<Texture2D> decrement = get_theme_icon("decrement"); int header_width = get_size().width - side_margin * 2; // Find the width of the header area. @@ -262,28 +262,28 @@ void TabContainer::_notification(int p_what) { Size2 size = get_size(); // Draw only the tab area if the header is hidden. - Ref<StyleBox> panel = get_stylebox("panel"); + Ref<StyleBox> panel = get_theme_stylebox("panel"); if (!tabs_visible) { panel->draw(canvas, Rect2(0, 0, size.width, size.height)); return; } Vector<Control *> tabs = _get_tabs(); - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<Texture2D> increment = get_icon("increment"); - Ref<Texture2D> increment_hl = get_icon("increment_highlight"); - Ref<Texture2D> decrement = get_icon("decrement"); - Ref<Texture2D> decrement_hl = get_icon("decrement_highlight"); - Ref<Texture2D> menu = get_icon("menu"); - Ref<Texture2D> menu_hl = get_icon("menu_highlight"); - Ref<Font> font = get_font("font"); - Color font_color_fg = get_color("font_color_fg"); - Color font_color_bg = get_color("font_color_bg"); - Color font_color_disabled = get_color("font_color_disabled"); - int side_margin = get_constant("side_margin"); - int icon_text_distance = get_constant("hseparation"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<Texture2D> increment = get_theme_icon("increment"); + Ref<Texture2D> increment_hl = get_theme_icon("increment_highlight"); + Ref<Texture2D> decrement = get_theme_icon("decrement"); + Ref<Texture2D> decrement_hl = get_theme_icon("decrement_highlight"); + Ref<Texture2D> menu = get_theme_icon("menu"); + Ref<Texture2D> menu_hl = get_theme_icon("menu_highlight"); + Ref<Font> font = get_theme_font("font"); + Color font_color_fg = get_theme_color("font_color_fg"); + Color font_color_bg = get_theme_color("font_color_bg"); + Color font_color_disabled = get_theme_color("font_color_disabled"); + int side_margin = get_theme_constant("side_margin"); + int icon_text_distance = get_theme_constant("hseparation"); // Find out start and width of the header area. int header_x = side_margin; @@ -458,7 +458,7 @@ int TabContainer::_get_tab_width(int p_index) const { return 0; // Get the width of the text displayed on the tab. - Ref<Font> font = get_font("font"); + Ref<Font> font = get_theme_font("font"); String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(control->get_name()); int width = font->get_string_size(text).width; @@ -468,14 +468,14 @@ int TabContainer::_get_tab_width(int p_index) const { if (icon.is_valid()) { width += icon->get_width(); if (text != "") - width += get_constant("hseparation"); + width += get_theme_constant("hseparation"); } } // Respect a minimum size. - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); if (get_tab_disabled(p_index)) { width += tab_disabled->get_minimum_size().width; } else if (p_index == current) { @@ -530,7 +530,7 @@ void TabContainer::add_child_notify(Node *p_child) { c->set_anchors_and_margins_preset(Control::PRESET_WIDE); if (tabs_visible) c->set_margin(MARGIN_TOP, _get_top_margin()); - Ref<StyleBox> sb = get_stylebox("panel"); + Ref<StyleBox> sb = get_theme_stylebox("panel"); c->set_margin(Margin(MARGIN_TOP), c->get_margin(Margin(MARGIN_TOP)) + sb->get_margin(Margin(MARGIN_TOP))); c->set_margin(Margin(MARGIN_LEFT), c->get_margin(Margin(MARGIN_LEFT)) + sb->get_margin(Margin(MARGIN_LEFT))); c->set_margin(Margin(MARGIN_RIGHT), c->get_margin(Margin(MARGIN_RIGHT)) - sb->get_margin(Margin(MARGIN_RIGHT))); @@ -554,7 +554,7 @@ void TabContainer::set_current_tab(int p_current) { int pending_previous = current; current = p_current; - Ref<StyleBox> sb = get_stylebox("panel"); + Ref<StyleBox> sb = get_theme_stylebox("panel"); Vector<Control *> tabs = _get_tabs(); for (int i = 0; i < tabs.size(); i++) { @@ -745,12 +745,12 @@ int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const { int right_ofs = 0; if (popup) { - Ref<Texture2D> menu = get_icon("menu"); + Ref<Texture2D> menu = get_theme_icon("menu"); right_ofs += menu->get_width(); } if (buttons_visible_cache) { - Ref<Texture2D> increment = get_icon("increment"); - Ref<Texture2D> decrement = get_icon("decrement"); + Ref<Texture2D> increment = get_theme_icon("increment"); + Ref<Texture2D> decrement = get_theme_icon("decrement"); right_ofs += increment->get_width() + decrement->get_width(); } if (p_point.x > size.width - right_ofs) { @@ -933,17 +933,17 @@ Size2 TabContainer::get_minimum_size() const { ms.y = MAX(ms.y, cms.y); } - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<Font> font = get_theme_font("font"); if (tabs_visible) { ms.y += MAX(MAX(tab_bg->get_minimum_size().y, tab_fg->get_minimum_size().y), tab_disabled->get_minimum_size().y); ms.y += font->get_height(); } - Ref<StyleBox> sb = get_stylebox("panel"); + Ref<StyleBox> sb = get_theme_stylebox("panel"); ms += sb->get_minimum_size(); return ms; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 901408919a..ea6d44e3a7 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -37,10 +37,10 @@ Size2 Tabs::get_minimum_size() const { - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<Font> font = get_theme_font("font"); Size2 ms(0, MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height) + font->get_height()); @@ -50,7 +50,7 @@ Size2 Tabs::get_minimum_size() const { if (tex.is_valid()) { ms.height = MAX(ms.height, tex->get_size().height); if (tabs[i].text != "") - ms.width += get_constant("hseparation"); + ms.width += get_theme_constant("hseparation"); } ms.width += Math::ceil(font->get_string_size(tabs[i].xl_text).width); @@ -65,15 +65,15 @@ Size2 Tabs::get_minimum_size() const { if (tabs[i].right_button.is_valid()) { Ref<Texture2D> rb = tabs[i].right_button; Size2 bms = rb->get_size(); - bms.width += get_constant("hseparation"); + bms.width += get_theme_constant("hseparation"); ms.width += bms.width; ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height); } if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { - Ref<Texture2D> cb = get_icon("close"); + Ref<Texture2D> cb = get_theme_icon("close"); Size2 bms = cb->get_size(); - bms.width += get_constant("hseparation"); + bms.width += get_theme_constant("hseparation"); ms.width += bms.width; ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height); } @@ -94,8 +94,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { highlight_arrow = -1; if (buttons_visible) { - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); @@ -163,8 +163,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { if (buttons_visible) { - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); @@ -238,14 +238,14 @@ void Tabs::_notification(int p_what) { _update_cache(); RID ci = get_canvas_item(); - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<Font> font = get_font("font"); - Color color_fg = get_color("font_color_fg"); - Color color_bg = get_color("font_color_bg"); - Color color_disabled = get_color("font_color_disabled"); - Ref<Texture2D> close = get_icon("close"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<Font> font = get_theme_font("font"); + Color color_fg = get_theme_color("font_color_fg"); + Color color_bg = get_theme_color("font_color_bg"); + Color color_disabled = get_theme_color("font_color_disabled"); + Ref<Texture2D> close = get_theme_icon("close"); int h = get_size().height; int w = 0; @@ -267,10 +267,10 @@ void Tabs::_notification(int p_what) { w = 0; } - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); - Ref<Texture2D> incr_hl = get_icon("increment_highlight"); - Ref<Texture2D> decr_hl = get_icon("decrement_highlight"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); + Ref<Texture2D> incr_hl = get_theme_icon("increment_highlight"); + Ref<Texture2D> decr_hl = get_theme_icon("decrement_highlight"); int limit = get_size().width - incr->get_size().width - decr->get_size().width; @@ -318,7 +318,7 @@ void Tabs::_notification(int p_what) { icon->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); if (tabs[i].text != "") - w += icon->get_width() + get_constant("hseparation"); + w += icon->get_width() + get_theme_constant("hseparation"); } font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].xl_text, col, tabs[i].size_text); @@ -327,10 +327,10 @@ void Tabs::_notification(int p_what) { if (tabs[i].right_button.is_valid()) { - Ref<StyleBox> style = get_stylebox("button"); + Ref<StyleBox> style = get_theme_stylebox("button"); Ref<Texture2D> rb = tabs[i].right_button; - w += get_constant("hseparation"); + w += get_theme_constant("hseparation"); Rect2 rb_rect; rb_rect.size = style->get_minimum_size() + rb->get_size(); @@ -339,7 +339,7 @@ void Tabs::_notification(int p_what) { if (rb_hover == i) { if (rb_pressing) - get_stylebox("button_pressed")->draw(ci, rb_rect); + get_theme_stylebox("button_pressed")->draw(ci, rb_rect); else style->draw(ci, rb_rect); } @@ -351,10 +351,10 @@ void Tabs::_notification(int p_what) { if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { - Ref<StyleBox> style = get_stylebox("button"); + Ref<StyleBox> style = get_theme_stylebox("button"); Ref<Texture2D> cb = close; - w += get_constant("hseparation"); + w += get_theme_constant("hseparation"); Rect2 cb_rect; cb_rect.size = style->get_minimum_size() + cb->get_size(); @@ -363,7 +363,7 @@ void Tabs::_notification(int p_what) { if (!tabs[i].disabled && cb_hover == i) { if (cb_pressing) - get_stylebox("button_pressed")->draw(ci, cb_rect); + get_theme_stylebox("button_pressed")->draw(ci, cb_rect); else style->draw(ci, cb_rect); } @@ -532,12 +532,12 @@ void Tabs::_update_hover() { } void Tabs::_update_cache() { - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<Font> font = get_font("font"); - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<Font> font = get_theme_font("font"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); int w = 0; @@ -577,12 +577,12 @@ void Tabs::_update_cache() { slen = m_width - (sb->get_margin(MARGIN_LEFT) + sb->get_margin(MARGIN_RIGHT)); if (tabs[i].icon.is_valid()) { slen -= tabs[i].icon->get_width(); - slen -= get_constant("hseparation"); + slen -= get_theme_constant("hseparation"); } if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { - Ref<Texture2D> cb = get_icon("close"); + Ref<Texture2D> cb = get_theme_icon("close"); slen -= cb->get_width(); - slen -= get_constant("hseparation"); + slen -= get_theme_constant("hseparation"); } slen = MAX(slen, 1); lsize = m_width; @@ -799,10 +799,10 @@ int Tabs::get_tab_width(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0); - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); - Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); - Ref<Font> font = get_font("font"); + Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); + Ref<Font> font = get_theme_font("font"); int x = 0; @@ -810,7 +810,7 @@ int Tabs::get_tab_width(int p_idx) const { if (tex.is_valid()) { x += tex->get_width(); if (tabs[p_idx].text != "") - x += get_constant("hseparation"); + x += get_theme_constant("hseparation"); } x += Math::ceil(font->get_string_size(tabs[p_idx].xl_text).width); @@ -825,13 +825,13 @@ int Tabs::get_tab_width(int p_idx) const { if (tabs[p_idx].right_button.is_valid()) { Ref<Texture2D> rb = tabs[p_idx].right_button; x += rb->get_width(); - x += get_constant("hseparation"); + x += get_theme_constant("hseparation"); } if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current)) { - Ref<Texture2D> cb = get_icon("close"); + Ref<Texture2D> cb = get_theme_icon("close"); x += cb->get_width(); - x += get_constant("hseparation"); + x += get_theme_constant("hseparation"); } return x; @@ -842,8 +842,8 @@ void Tabs::_ensure_no_over_offset() { if (!is_inside_tree()) return; - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); @@ -885,8 +885,8 @@ void Tabs::ensure_tab_visible(int p_idx) { } int prev_offset = offset; - Ref<Texture2D> incr = get_icon("increment"); - Ref<Texture2D> decr = get_icon("decrement"); + Ref<Texture2D> incr = get_theme_icon("increment"); + Ref<Texture2D> decr = get_theme_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); for (int i = offset; i <= p_idx; i++) { if (tabs[i].ofs_cache + tabs[i].size_cache > limit) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index cdc2430eb5..fb477ee3b4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -30,13 +30,13 @@ #include "text_edit.h" +#include "core/input/input_filter.h" #include "core/message_queue.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/project_settings.h" #include "core/script_language.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #ifdef TOOLS_ENABLED #include "editor/editor_scale.h" @@ -446,7 +446,7 @@ void TextEdit::_click_selection_held() { // Warning: is_mouse_button_pressed(BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD // and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem. // I'm unsure if there's an actual fix that doesn't have a ton of side effects. - if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) { + if (InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) { switch (selection.selecting_mode) { case Selection::MODE_POINTER: { _update_selection_mode_pointer(); @@ -639,12 +639,12 @@ void TextEdit::_notification(int p_what) { _update_wrap_at(); syntax_highlighting_cache.clear(); } break; - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + case NOTIFICATION_WM_FOCUS_IN: { window_has_focus = true; draw_caret = true; update(); } break; - case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_FOCUS_OUT: { window_has_focus = false; draw_caret = false; update(); @@ -1584,11 +1584,11 @@ void TextEdit::_notification(int p_what) { bool completion_below = false; if (completion_active && completion_options.size() > 0) { // Code completion box. - Ref<StyleBox> csb = get_stylebox("completion"); - int maxlines = get_constant("completion_lines"); - int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x; - int scrollw = get_constant("completion_scroll_width"); - Color scrollc = get_color("completion_scroll_color"); + Ref<StyleBox> csb = get_theme_stylebox("completion"); + int maxlines = get_theme_constant("completion_lines"); + int cmax_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x').x; + int scrollw = get_theme_constant("completion_scroll_width"); + Color scrollc = get_theme_color("completion_scroll_color"); const int completion_options_size = completion_options.size(); int lines = MIN(completion_options_size, maxlines); @@ -1607,7 +1607,7 @@ void TextEdit::_notification(int p_what) { } // Add space for completion icons. - const int icon_hsep = get_constant("hseparation", "ItemList"); + const int icon_hsep = get_theme_constant("hseparation", "ItemList"); Size2 icon_area_size(get_row_height(), get_row_height()); w += icon_area_size.width + icon_hsep; @@ -1694,9 +1694,9 @@ void TextEdit::_notification(int p_what) { if (show_hint) { - Ref<StyleBox> sb = get_stylebox("panel", "TooltipPanel"); + Ref<StyleBox> sb = get_theme_stylebox("panel", "TooltipPanel"); Ref<Font> font = cache.font; - Color font_color = get_color("font_color", "TooltipLabel"); + Color font_color = get_theme_color("font_color", "TooltipLabel"); int max_w = 0; int sc = completion_hint.get_slice_count("\n"); @@ -1754,8 +1754,10 @@ void TextEdit::_notification(int p_what) { } if (has_focus()) { - OS::get_singleton()->set_ime_active(true); - OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos + Point2(0, get_row_height())); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); + DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos + Point2(0, get_row_height()), get_viewport()->get_window_id()); + } } } break; case NOTIFICATION_FOCUS_ENTER: { @@ -1766,12 +1768,14 @@ void TextEdit::_notification(int p_what) { draw_caret = true; } - OS::get_singleton()->set_ime_active(true); - Point2 cursor_pos = Point2(cursor_get_column(), cursor_get_line()) * get_row_height(); - OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); + Point2 cursor_pos = Point2(cursor_get_column(), cursor_get_line()) * get_row_height(); + DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); + } - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->show_virtual_keyboard(get_text(), get_global_rect()); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect()); } break; case NOTIFICATION_FOCUS_EXIT: { @@ -1779,19 +1783,21 @@ void TextEdit::_notification(int p_what) { caret_blink_timer->stop(); } - OS::get_singleton()->set_ime_position(Point2()); - OS::get_singleton()->set_ime_active(false); + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); + DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); + } ime_text = ""; ime_selection = Point2(); - if (OS::get_singleton()->has_virtual_keyboard()) - OS::get_singleton()->hide_virtual_keyboard(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + DisplayServer::get_singleton()->virtual_keyboard_hide(); } break; case MainLoop::NOTIFICATION_OS_IME_UPDATE: { if (has_focus()) { - ime_text = OS::get_singleton()->get_ime_text(); - ime_selection = OS::get_singleton()->get_ime_selection(); + ime_text = DisplayServer::get_singleton()->ime_get_text(); + ime_selection = DisplayServer::get_singleton()->ime_get_selection(); update(); } } break; @@ -2477,9 +2483,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - menu->set_position(get_global_transform().xform(get_local_mouse_position())); + menu->set_position(get_screen_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); - menu->set_scale(get_global_transform().get_scale()); + // menu->set_scale(get_global_transform().get_scale()); menu->popup(); grab_focus(); } @@ -2634,7 +2640,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_keycode() == KEY_PAGEUP) { - completion_index -= get_constant("completion_lines"); + completion_index -= get_theme_constant("completion_lines"); if (completion_index < 0) completion_index = 0; completion_current = completion_options[completion_index]; @@ -2645,7 +2651,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_keycode() == KEY_PAGEDOWN) { - completion_index += get_constant("completion_lines"); + completion_index += get_theme_constant("completion_lines"); if (completion_index >= completion_options.size()) completion_index = completion_options.size() - 1; completion_current = completion_options[completion_index]; @@ -3735,7 +3741,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (context_menu_enabled) { menu->set_position(get_global_transform().xform(_get_cursor_pixel_pos())); menu->set_size(Vector2(1, 1)); - menu->set_scale(get_global_transform().get_scale()); + // menu->set_scale(get_global_transform().get_scale()); menu->popup(); menu->grab_focus(); } @@ -5026,51 +5032,51 @@ void TextEdit::_toggle_draw_caret() { void TextEdit::_update_caches() { - cache.style_normal = get_stylebox("normal"); - cache.style_focus = get_stylebox("focus"); - cache.style_readonly = get_stylebox("read_only"); - cache.completion_background_color = get_color("completion_background_color"); - cache.completion_selected_color = get_color("completion_selected_color"); - cache.completion_existing_color = get_color("completion_existing_color"); - cache.completion_font_color = get_color("completion_font_color"); - cache.font = get_font("font"); - cache.caret_color = get_color("caret_color"); - cache.caret_background_color = get_color("caret_background_color"); - cache.line_number_color = get_color("line_number_color"); - cache.safe_line_number_color = get_color("safe_line_number_color"); - cache.font_color = get_color("font_color"); - cache.font_color_selected = get_color("font_color_selected"); - cache.font_color_readonly = get_color("font_color_readonly"); - cache.keyword_color = get_color("keyword_color"); - cache.function_color = get_color("function_color"); - cache.member_variable_color = get_color("member_variable_color"); - cache.number_color = get_color("number_color"); - cache.selection_color = get_color("selection_color"); - cache.mark_color = get_color("mark_color"); - cache.current_line_color = get_color("current_line_color"); - cache.line_length_guideline_color = get_color("line_length_guideline_color"); - cache.bookmark_color = get_color("bookmark_color"); - cache.breakpoint_color = get_color("breakpoint_color"); - cache.executing_line_color = get_color("executing_line_color"); - cache.code_folding_color = get_color("code_folding_color"); - cache.brace_mismatch_color = get_color("brace_mismatch_color"); - cache.word_highlighted_color = get_color("word_highlighted_color"); - cache.search_result_color = get_color("search_result_color"); - cache.search_result_border_color = get_color("search_result_border_color"); - cache.symbol_color = get_color("symbol_color"); - cache.background_color = get_color("background_color"); + cache.style_normal = get_theme_stylebox("normal"); + cache.style_focus = get_theme_stylebox("focus"); + cache.style_readonly = get_theme_stylebox("read_only"); + cache.completion_background_color = get_theme_color("completion_background_color"); + cache.completion_selected_color = get_theme_color("completion_selected_color"); + cache.completion_existing_color = get_theme_color("completion_existing_color"); + cache.completion_font_color = get_theme_color("completion_font_color"); + cache.font = get_theme_font("font"); + cache.caret_color = get_theme_color("caret_color"); + cache.caret_background_color = get_theme_color("caret_background_color"); + cache.line_number_color = get_theme_color("line_number_color"); + cache.safe_line_number_color = get_theme_color("safe_line_number_color"); + cache.font_color = get_theme_color("font_color"); + cache.font_color_selected = get_theme_color("font_color_selected"); + cache.font_color_readonly = get_theme_color("font_color_readonly"); + cache.keyword_color = get_theme_color("keyword_color"); + cache.function_color = get_theme_color("function_color"); + cache.member_variable_color = get_theme_color("member_variable_color"); + cache.number_color = get_theme_color("number_color"); + cache.selection_color = get_theme_color("selection_color"); + cache.mark_color = get_theme_color("mark_color"); + cache.current_line_color = get_theme_color("current_line_color"); + cache.line_length_guideline_color = get_theme_color("line_length_guideline_color"); + cache.bookmark_color = get_theme_color("bookmark_color"); + cache.breakpoint_color = get_theme_color("breakpoint_color"); + cache.executing_line_color = get_theme_color("executing_line_color"); + cache.code_folding_color = get_theme_color("code_folding_color"); + cache.brace_mismatch_color = get_theme_color("brace_mismatch_color"); + cache.word_highlighted_color = get_theme_color("word_highlighted_color"); + cache.search_result_color = get_theme_color("search_result_color"); + cache.search_result_border_color = get_theme_color("search_result_border_color"); + cache.symbol_color = get_theme_color("symbol_color"); + cache.background_color = get_theme_color("background_color"); #ifdef TOOLS_ENABLED - cache.line_spacing = get_constant("line_spacing") * EDSCALE; + cache.line_spacing = get_theme_constant("line_spacing") * EDSCALE; #else - cache.line_spacing = get_constant("line_spacing"); + cache.line_spacing = get_theme_constant("line_spacing"); #endif cache.row_height = cache.font->get_height() + cache.line_spacing; - cache.tab_icon = get_icon("tab"); - cache.space_icon = get_icon("space"); - cache.folded_icon = get_icon("folded"); - cache.can_fold_icon = get_icon("fold"); - cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons"); - cache.executing_icon = get_icon("MainPlay", "EditorIcons"); + cache.tab_icon = get_theme_icon("tab"); + cache.space_icon = get_theme_icon("space"); + cache.folded_icon = get_theme_icon("folded"); + cache.can_fold_icon = get_theme_icon("fold"); + cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons"); + cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons"); text.set_font(cache.font); if (syntax_highlighter) { @@ -5226,7 +5232,7 @@ void TextEdit::cut() { if (!selection.active) { String clipboard = text[cursor.line]; - OS::get_singleton()->set_clipboard(clipboard); + DisplayServer::get_singleton()->clipboard_set(clipboard); cursor_set_line(cursor.line); cursor_set_column(0); @@ -5244,7 +5250,7 @@ void TextEdit::cut() { } else { String clipboard = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); + DisplayServer::get_singleton()->clipboard_set(clipboard); _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); cursor_set_line(selection.from_line); // Set afterwards else it causes the view to be offset. @@ -5264,19 +5270,19 @@ void TextEdit::copy() { if (text[cursor.line].length() != 0) { String clipboard = _base_get_text(cursor.line, 0, cursor.line, text[cursor.line].length()); - OS::get_singleton()->set_clipboard(clipboard); + DisplayServer::get_singleton()->clipboard_set(clipboard); cut_copy_line = clipboard; } } else { String clipboard = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); + DisplayServer::get_singleton()->clipboard_set(clipboard); cut_copy_line = ""; } } void TextEdit::paste() { - String clipboard = OS::get_singleton()->get_clipboard(); + String clipboard = DisplayServer::get_singleton()->clipboard_get(); begin_complex_operation(); if (selection.active) { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 12b3d56938..653ac74164 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -30,13 +30,15 @@ #include "tree.h" +#include "core/input/input_filter.h" #include "core/math/math_funcs.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" #include "core/project_settings.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" + +#include "box_container.h" #ifdef TOOLS_ENABLED #include "editor/editor_scale.h" @@ -952,45 +954,45 @@ TreeItem::~TreeItem() { void Tree::update_cache() { - cache.font = get_font("font"); - cache.tb_font = get_font("title_button_font"); - cache.bg = get_stylebox("bg"); - cache.selected = get_stylebox("selected"); - cache.selected_focus = get_stylebox("selected_focus"); - cache.cursor = get_stylebox("cursor"); - cache.cursor_unfocus = get_stylebox("cursor_unfocused"); - cache.button_pressed = get_stylebox("button_pressed"); - - cache.checked = get_icon("checked"); - cache.unchecked = get_icon("unchecked"); - cache.arrow_collapsed = get_icon("arrow_collapsed"); - cache.arrow = get_icon("arrow"); - cache.select_arrow = get_icon("select_arrow"); - cache.updown = get_icon("updown"); - - cache.custom_button = get_stylebox("custom_button"); - cache.custom_button_hover = get_stylebox("custom_button_hover"); - cache.custom_button_pressed = get_stylebox("custom_button_pressed"); - cache.custom_button_font_highlight = get_color("custom_button_font_highlight"); - - cache.font_color = get_color("font_color"); - cache.font_color_selected = get_color("font_color_selected"); - cache.guide_color = get_color("guide_color"); - cache.drop_position_color = get_color("drop_position_color"); - cache.hseparation = get_constant("hseparation"); - cache.vseparation = get_constant("vseparation"); - cache.item_margin = get_constant("item_margin"); - cache.button_margin = get_constant("button_margin"); - cache.draw_guides = get_constant("draw_guides"); - cache.draw_relationship_lines = get_constant("draw_relationship_lines"); - cache.relationship_line_color = get_color("relationship_line_color"); - cache.scroll_border = get_constant("scroll_border"); - cache.scroll_speed = get_constant("scroll_speed"); - - cache.title_button = get_stylebox("title_button_normal"); - cache.title_button_pressed = get_stylebox("title_button_pressed"); - cache.title_button_hover = get_stylebox("title_button_hover"); - cache.title_button_color = get_color("title_button_color"); + cache.font = get_theme_font("font"); + cache.tb_font = get_theme_font("title_button_font"); + cache.bg = get_theme_stylebox("bg"); + cache.selected = get_theme_stylebox("selected"); + cache.selected_focus = get_theme_stylebox("selected_focus"); + cache.cursor = get_theme_stylebox("cursor"); + cache.cursor_unfocus = get_theme_stylebox("cursor_unfocused"); + cache.button_pressed = get_theme_stylebox("button_pressed"); + + cache.checked = get_theme_icon("checked"); + cache.unchecked = get_theme_icon("unchecked"); + cache.arrow_collapsed = get_theme_icon("arrow_collapsed"); + cache.arrow = get_theme_icon("arrow"); + cache.select_arrow = get_theme_icon("select_arrow"); + cache.updown = get_theme_icon("updown"); + + cache.custom_button = get_theme_stylebox("custom_button"); + cache.custom_button_hover = get_theme_stylebox("custom_button_hover"); + cache.custom_button_pressed = get_theme_stylebox("custom_button_pressed"); + cache.custom_button_font_highlight = get_theme_color("custom_button_font_highlight"); + + cache.font_color = get_theme_color("font_color"); + cache.font_color_selected = get_theme_color("font_color_selected"); + cache.guide_color = get_theme_color("guide_color"); + cache.drop_position_color = get_theme_color("drop_position_color"); + cache.hseparation = get_theme_constant("hseparation"); + cache.vseparation = get_theme_constant("vseparation"); + cache.item_margin = get_theme_constant("item_margin"); + cache.button_margin = get_theme_constant("button_margin"); + cache.draw_guides = get_theme_constant("draw_guides"); + cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines"); + cache.relationship_line_color = get_theme_color("relationship_line_color"); + cache.scroll_border = get_theme_constant("scroll_border"); + cache.scroll_speed = get_theme_constant("scroll_speed"); + + cache.title_button = get_theme_stylebox("title_button_normal"); + cache.title_button_pressed = get_theme_stylebox("title_button_pressed"); + cache.title_button_hover = get_theme_stylebox("title_button_hover"); + cache.title_button_color = get_theme_color("title_button_color"); v_scroll->set_custom_step(cache.font->get_height()); } @@ -1291,7 +1293,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } - Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_color(p_item->cells[i].selected ? "font_color_selected" : "font_color"); + Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_color_selected" : "font_color"); Color icon_col = p_item->cells[i].icon_color; Point2i text_pos = item_rect.position; @@ -1423,7 +1425,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].custom_button) { if (cache.hover_item == p_item && cache.hover_cell == i) { - if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { draw_style_box(cache.custom_button_pressed, ir); } else { draw_style_box(cache.custom_button_hover, ir); @@ -1659,7 +1661,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) { void Tree::_range_click_timeout() { - if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (range_item_last && !range_drag_enabled && InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { Point2 pos = get_local_mouse_position() - cache.bg->get_offset(); if (show_column_titles) { @@ -2046,9 +2048,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool void Tree::_text_editor_modal_close() { - if (Input::get_singleton()->is_key_pressed(KEY_ESCAPE) || - Input::get_singleton()->is_key_pressed(KEY_KP_ENTER) || - Input::get_singleton()->is_key_pressed(KEY_ENTER)) { + if (InputFilter::get_singleton()->is_key_pressed(KEY_ESCAPE) || + InputFilter::get_singleton()->is_key_pressed(KEY_KP_ENTER) || + InputFilter::get_singleton()->is_key_pressed(KEY_ENTER)) { return; } @@ -2056,13 +2058,12 @@ void Tree::_text_editor_modal_close() { if (value_editor->has_point(value_editor->get_local_mouse_position())) return; - text_editor_enter(text_editor->get_text()); + _text_editor_enter(text_editor->get_text()); } -void Tree::text_editor_enter(String p_text) { +void Tree::_text_editor_enter(String p_text) { - text_editor->hide(); - value_editor->hide(); + popup_editor->hide(); if (!popup_edited_item) return; @@ -2531,7 +2532,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { range_drag_enabled = true; range_drag_capture_pos = cpos; range_drag_base = popup_edited_item->get_range(popup_edited_item_col); - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_CAPTURED); } } else { @@ -2593,7 +2594,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { if (range_drag_enabled) { range_drag_enabled = false; - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE); warp_mouse(range_drag_capture_pos); } else { Rect2 rect = get_selected()->get_meta("__focus_rect"); @@ -2703,7 +2704,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { drag_accum = 0; //last_drag_accum=0; drag_from = v_scroll->get_value(); - drag_touching = OS::get_singleton()->has_touchscreen_ui_hint(); + drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); drag_touching_deaccel = false; if (drag_touching) { set_physics_process_internal(true); @@ -2806,20 +2807,23 @@ bool Tree::edit_selected() { } else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) { + Rect2 popup_rect; + Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2); - Point2i textedpos = get_global_position() + rect.position - ofs; + + Point2i textedpos = get_screen_position() + rect.position - ofs; cache.text_editor_position = textedpos; - text_editor->set_position(textedpos); - text_editor->set_size(rect.size); + popup_rect.position = textedpos; + popup_rect.size = rect.size; text_editor->clear(); text_editor->set_text(c.mode == TreeItem::CELL_MODE_STRING ? c.text : String::num(c.val, Math::range_step_decimals(c.step))); text_editor->select_all(); if (c.mode == TreeItem::CELL_MODE_RANGE) { - value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height)); - value_editor->set_size(Size2(rect.size.width, 1)); - value_editor->show_modal(); + popup_rect.size.y += value_editor->get_minimum_size().height; + + value_editor->show(); updating_value_editor = true; value_editor->set_min(c.min); value_editor->set_max(c.max); @@ -2827,10 +2831,17 @@ bool Tree::edit_selected() { value_editor->set_value(c.val); value_editor->set_exp_ratio(c.expr); updating_value_editor = false; + } else { + value_editor->hide(); } - text_editor->show_modal(); + popup_editor->set_position(popup_rect.position); + popup_editor->set_size(popup_rect.size); + popup_editor->popup(); + popup_editor->child_controls_changed(); + text_editor->grab_focus(); + return true; } @@ -3011,7 +3022,7 @@ void Tree::_notification(int p_what) { RID ci = get_canvas_item(); Ref<StyleBox> bg = cache.bg; - Ref<StyleBox> bg_focus = get_stylebox("bg_focus"); + Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus"); Point2 draw_ofs; draw_ofs += bg->get_offset(); @@ -3234,7 +3245,7 @@ void Tree::clear() { if (pressing_for_editor) { if (range_drag_enabled) { range_drag_enabled = false; - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE); warp_mouse(range_drag_capture_pos); } pressing_for_editor = false; @@ -4020,14 +4031,23 @@ Tree::Tree() { popup_menu = memnew(PopupMenu); popup_menu->hide(); add_child(popup_menu); - popup_menu->set_as_toplevel(true); + // popup_menu->set_as_toplevel(true); + + popup_editor = memnew(PopupPanel); + popup_editor->set_wrap_controls(true); + add_child(popup_editor); + popup_editor_vb = memnew(VBoxContainer); + popup_editor->add_child(popup_editor_vb); + popup_editor_vb->add_theme_constant_override("separation", 0); + popup_editor_vb->set_anchors_and_margins_preset(PRESET_WIDE); text_editor = memnew(LineEdit); - add_child(text_editor); - text_editor->set_as_toplevel(true); - text_editor->hide(); + popup_editor_vb->add_child(text_editor); + text_editor->set_v_size_flags(SIZE_EXPAND_FILL); + text_editor->set_h_size_flags(SIZE_EXPAND_FILL); value_editor = memnew(HSlider); - add_child(value_editor); - value_editor->set_as_toplevel(true); + value_editor->set_v_size_flags(SIZE_EXPAND_FILL); + value_editor->set_h_size_flags(SIZE_EXPAND_FILL); + popup_editor_vb->add_child(value_editor); value_editor->hide(); h_scroll = memnew(HScrollBar); @@ -4042,13 +4062,11 @@ Tree::Tree() { h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); - text_editor->connect("text_entered", callable_mp(this, &Tree::text_editor_enter)); - text_editor->connect("modal_closed", callable_mp(this, &Tree::_text_editor_modal_close)); + text_editor->connect("text_entered", callable_mp(this, &Tree::_text_editor_enter)); + popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_modal_close)); popup_menu->connect("id_pressed", callable_mp(this, &Tree::popup_select)); value_editor->connect("value_changed", callable_mp(this, &Tree::value_editor_changed)); - value_editor->set_as_toplevel(true); - text_editor->set_as_toplevel(true); set_notify_transform(true); updating_value_editor = false; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index b179c5bcba..becbe76598 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -290,6 +290,8 @@ public: VARIANT_ENUM_CAST(TreeItem::TreeCellMode); VARIANT_ENUM_CAST(TreeItem::TextAlign); +class VBoxContainer; + class Tree : public Control { GDCLASS(Tree, Control); @@ -359,6 +361,10 @@ private: }; bool show_column_titles; + + VBoxContainer *popup_editor_vb; + + PopupPanel *popup_editor; LineEdit *text_editor; HSlider *value_editor; bool updating_value_editor; @@ -379,7 +385,7 @@ private: int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = NULL, bool *r_in_range = NULL, bool p_force_deselect = false); int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod); - void text_editor_enter(String p_text); + void _text_editor_enter(String p_text); void _text_editor_modal_close(); void value_editor_changed(double p_value); diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index a76f2924d3..7ce1d9e551 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -40,7 +40,7 @@ Size2 ViewportContainer::get_minimum_size() const { Size2 ms; for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c) continue; @@ -77,7 +77,7 @@ void ViewportContainer::set_stretch_shrink(int p_shrink) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c) continue; @@ -101,7 +101,7 @@ void ViewportContainer::_notification(int p_what) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c) continue; @@ -113,14 +113,14 @@ void ViewportContainer::_notification(int p_what) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c) continue; if (is_visible_in_tree()) - c->set_update_mode(Viewport::UPDATE_ALWAYS); + c->set_update_mode(SubViewport::UPDATE_ALWAYS); else - c->set_update_mode(Viewport::UPDATE_DISABLED); + c->set_update_mode(SubViewport::UPDATE_DISABLED); c->set_handle_input_locally(false); //do not handle input locally here } @@ -130,7 +130,7 @@ void ViewportContainer::_notification(int p_what) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c) continue; @@ -159,7 +159,7 @@ void ViewportContainer::_input(const Ref<InputEvent> &p_event) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c || c->is_input_disabled()) continue; @@ -184,7 +184,7 @@ void ViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) { for (int i = 0; i < get_child_count(); i++) { - Viewport *c = Object::cast_to<Viewport>(get_child(i)); + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); if (!c || c->is_input_disabled()) continue; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 973dff07d2..b882b9ead6 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2950,9 +2950,9 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN); BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT); - BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST); BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); - BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED); BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_WM_ABOUT); diff --git a/scene/main/node.h b/scene/main/node.h index d1f75b71ec..cf25a92be6 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -244,13 +244,16 @@ public: NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, NOTIFICATION_POST_ENTER_TREE = 27, //keep these linked to node - NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER, - NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT, - NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN, - NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT, - NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST, - NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST, - NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST, + + NOTIFICATION_WM_MOUSE_ENTER = 1002, + NOTIFICATION_WM_MOUSE_EXIT = 1003, + NOTIFICATION_WM_FOCUS_IN = 1004, + NOTIFICATION_WM_FOCUS_OUT = 1005, + NOTIFICATION_WM_CLOSE_REQUEST = 1006, + NOTIFICATION_WM_GO_BACK_REQUEST = 1007, + NOTIFICATION_WM_SIZE_CHANGED = 1008, + NOTIFICATION_WM_DPI_CHANGE = 1009, + NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING, NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED, NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT, diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index f472de220b..fad10524b9 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -31,6 +31,7 @@ #include "scene_tree.h" #include "core/debugger/engine_debugger.h" +#include "core/input/input_filter.h" #include "core/io/marshalls.h" #include "core/io/resource_loader.h" #include "core/message_queue.h" @@ -39,7 +40,6 @@ #include "core/os/os.h" #include "core/print_string.h" #include "core/project_settings.h" -#include "main/input_default.h" #include "node.h" #include "scene/debugger/scene_debugger.h" #include "scene/resources/dynamic_font.h" @@ -47,10 +47,11 @@ #include "scene/resources/mesh.h" #include "scene/resources/packed_scene.h" #include "scene/scene_string_names.h" +#include "servers/display_server.h" #include "servers/navigation_server.h" #include "servers/physics_2d_server.h" #include "servers/physics_server.h" -#include "viewport.h" +#include "window.h" #include <stdio.h> @@ -397,69 +398,6 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const set_group_flags(0, p_group, p_name, p_value); } -void SceneTree::set_input_as_handled() { - - input_handled = true; -} - -void SceneTree::input_text(const String &p_text) { - - root_lock++; - - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input_text", p_text); //special one for GUI, as controls use their own process check - - root_lock--; -} - -bool SceneTree::is_input_handled() { - return input_handled; -} - -void SceneTree::input_event(const Ref<InputEvent> &p_event) { - - if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event))) - return; //avoid joy input on editor - - current_event++; - root_lock++; - - input_handled = false; - - // Don't make const ref unless you can find and fix what caused GH-34691. - Ref<InputEvent> ev = p_event; - - MainLoop::input_event(ev); - - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input", ev); //special one for GUI, as controls use their own process check - - if (EngineDebugger::is_active()) { - //quit from game window using F8 - Ref<InputEventKey> k = ev; - if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) { - EngineDebugger::get_singleton()->send_message("request_quit", Array()); - } - } - - _flush_ugc(); - root_lock--; - //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness - - root_lock++; - - if (!input_handled) { - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check - _flush_ugc(); - // input_handled = true; - no reason to set this as handled - root_lock--; - //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness - } else { - // input_handled = true; - no reason to set this as handled - root_lock--; - } - - _call_idle_callbacks(); -} - void SceneTree::init() { initialized = true; root->_set_tree(this); @@ -493,14 +431,6 @@ bool SceneTree::iteration(float p_time) { return _quit; } -void SceneTree::_update_font_oversampling(float p_ratio) { - - if (use_font_oversampling) { - DynamicFontAtSize::font_oversampling = p_ratio; - DynamicFont::update_oversampling(); - } -} - bool SceneTree::idle(float p_time) { //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); @@ -526,15 +456,6 @@ bool SceneTree::idle(float p_time) { _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); _notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS); - Size2 win_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); - - if (win_size != last_screen_size) { - - last_screen_size = win_size; - _update_root_rect(); - emit_signal("screen_resized"); - } - _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications @@ -642,59 +563,36 @@ void SceneTree::quit(int p_exit_code) { _quit = true; } -void SceneTree::_notification(int p_notification) { - - switch (p_notification) { - - case NOTIFICATION_WM_QUIT_REQUEST: { - - get_root()->propagate_notification(p_notification); - - if (accept_quit) { - _quit = true; - break; - } - } break; - - case NOTIFICATION_WM_GO_BACK_REQUEST: { - - get_root()->propagate_notification(p_notification); +void SceneTree::_main_window_close() { - if (quit_on_go_back) { - _quit = true; - break; - } - } break; + if (accept_quit) { + _quit = true; + } +} +void SceneTree::_main_window_go_back() { + if (quit_on_go_back) { + _quit = true; + } +} - case NOTIFICATION_WM_FOCUS_IN: { +void SceneTree::_main_window_focus_in() { + InputFilter *id = InputFilter::get_singleton(); + if (id) { + id->ensure_touch_mouse_raised(); + } +} - InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); - if (id) { - id->ensure_touch_mouse_raised(); - } +void SceneTree::_notification(int p_notification) { - get_root()->propagate_notification(p_notification); - } break; + switch (p_notification) { case NOTIFICATION_TRANSLATION_CHANGED: { if (!Engine::get_singleton()->is_editor_hint()) { get_root()->propagate_notification(p_notification); } } break; - - case NOTIFICATION_WM_UNFOCUS_REQUEST: { - - notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST); - - get_root()->propagate_notification(p_notification); - - } break; - case NOTIFICATION_OS_MEMORY_WARNING: case NOTIFICATION_OS_IME_UPDATE: - case NOTIFICATION_WM_MOUSE_ENTER: - case NOTIFICATION_WM_MOUSE_EXIT: - case NOTIFICATION_WM_FOCUS_OUT: case NOTIFICATION_WM_ABOUT: case NOTIFICATION_CRASH: case NOTIFICATION_APP_RESUMED: @@ -910,7 +808,7 @@ bool SceneTree::is_paused() const { return pause; } -void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input) { +void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) { Map<StringName, Group>::Element *E = group_map.find(p_group); if (!E) @@ -919,7 +817,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p if (g.nodes.empty()) return; - _update_group_order(g); + _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); //copy, so copy on write happens in case something is removed from process while being called //performance is not lost because only if something is added/removed the vector is copied. @@ -928,15 +826,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p int node_count = nodes_copy.size(); Node **nodes = nodes_copy.ptrw(); - Variant arg = p_input; - const Variant *v[1] = { &arg }; - call_lock++; - for (int i = node_count - 1; i >= 0; i--) { - - if (input_handled) - break; + for (int i = 0; i < node_count; i++) { Node *n = nodes[i]; if (call_lock && call_skip.has(n)) @@ -944,8 +836,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p if (!n->can_process()) continue; + if (!n->can_process_notification(p_notification)) + continue; - n->call_multilevel(p_method, (const Variant **)v, 1); + n->notification(p_notification); //ERR_FAIL_COND(node_count != g.nodes.size()); } @@ -954,7 +848,18 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p call_skip.clear(); } -void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) { +/* +void SceneMainLoop::_update_listener_2d() { + + if (listener_2d.is_valid()) { + + SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() ); + } + +} +*/ + +void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) { Map<StringName, Group>::Element *E = group_map.find(p_group); if (!E) @@ -963,7 +868,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio if (g.nodes.empty()) return; - _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + _update_group_order(g); //copy, so copy on write happens in case something is removed from process while being called //performance is not lost because only if something is added/removed the vector is copied. @@ -972,9 +877,15 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio int node_count = nodes_copy.size(); Node **nodes = nodes_copy.ptrw(); + Variant arg = p_input; + const Variant *v[1] = { &arg }; + call_lock++; - for (int i = 0; i < node_count; i++) { + for (int i = node_count - 1; i >= 0; i--) { + + if (p_viewport->is_input_handled()) + break; Node *n = nodes[i]; if (call_lock && call_skip.has(n)) @@ -982,10 +893,8 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio if (!n->can_process()) continue; - if (!n->can_process_notification(p_notification)) - continue; - n->notification(p_notification); + n->call_multilevel(p_method, (const Variant **)v, 1); //ERR_FAIL_COND(node_count != g.nodes.size()); } @@ -993,18 +902,6 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio if (call_lock == 0) call_skip.clear(); } - -/* -void SceneMainLoop::_update_listener_2d() { - - if (listener_2d.is_valid()) { - - SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() ); - } - -} -*/ - Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; @@ -1129,129 +1026,6 @@ int SceneTree::get_node_count() const { return node_count; } -void SceneTree::_update_root_rect() { - - if (stretch_mode == STRETCH_MODE_DISABLED) { - - _update_font_oversampling(1.0); - root->set_size((last_screen_size / stretch_shrink).floor()); - root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size)); - root->set_size_override_stretch(false); - root->set_size_override(false, Size2()); - root->update_canvas_items(); - return; //user will take care - } - - //actual screen video mode - Size2 video_mode = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); - Size2 desired_res = stretch_min; - - Size2 viewport_size; - Size2 screen_size; - - float viewport_aspect = desired_res.aspect(); - float video_mode_aspect = video_mode.aspect(); - - if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) { - WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'."); - } - - if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { - //same aspect or ignore aspect - viewport_size = desired_res; - screen_size = video_mode; - } else if (viewport_aspect < video_mode_aspect) { - // screen ratio is smaller vertically - - if (stretch_aspect == STRETCH_ASPECT_KEEP_HEIGHT || stretch_aspect == STRETCH_ASPECT_EXPAND) { - - //will stretch horizontally - viewport_size.x = desired_res.y * video_mode_aspect; - viewport_size.y = desired_res.y; - screen_size = video_mode; - - } else { - //will need black bars - viewport_size = desired_res; - screen_size.x = video_mode.y * viewport_aspect; - screen_size.y = video_mode.y; - } - } else { - //screen ratio is smaller horizontally - if (stretch_aspect == STRETCH_ASPECT_KEEP_WIDTH || stretch_aspect == STRETCH_ASPECT_EXPAND) { - - //will stretch horizontally - viewport_size.x = desired_res.x; - viewport_size.y = desired_res.x / video_mode_aspect; - screen_size = video_mode; - - } else { - //will need black bars - viewport_size = desired_res; - screen_size.x = video_mode.x; - screen_size.y = video_mode.x / viewport_aspect; - } - } - - screen_size = screen_size.floor(); - viewport_size = viewport_size.floor(); - - Size2 margin; - Size2 offset; - //black bars and margin - if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.x < video_mode.x) { - margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); - VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0); - offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); - } else if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.y < video_mode.y) { - margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); - VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y); - offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); - } else { - VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0); - } - - switch (stretch_mode) { - case STRETCH_MODE_DISABLED: { - // Already handled above - _update_font_oversampling(1.0); - } break; - case STRETCH_MODE_2D: { - - _update_font_oversampling(screen_size.x / viewport_size.x); //screen / viewport radio drives oversampling - root->set_size((screen_size / stretch_shrink).floor()); - root->set_attach_to_screen_rect(Rect2(margin, screen_size)); - root->set_size_override_stretch(true); - root->set_size_override(true, (viewport_size / stretch_shrink).floor()); - root->update_canvas_items(); //force them to update just in case - - } break; - case STRETCH_MODE_VIEWPORT: { - - _update_font_oversampling(1.0); - root->set_size((viewport_size / stretch_shrink).floor()); - root->set_attach_to_screen_rect(Rect2(margin, screen_size)); - root->set_size_override_stretch(false); - root->set_size_override(false, Size2()); - root->update_canvas_items(); //force them to update just in case - - if (use_font_oversampling) { - WARN_PRINT("Font oversampling does not work in 'Viewport' stretch mode, only '2D'."); - } - - } break; - } -} - -void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink) { - - stretch_mode = p_mode; - stretch_aspect = p_aspect; - stretch_min = p_minsize; - stretch_shrink = p_shrink; - _update_root_rect(); -} - void SceneTree::set_edited_scene_root(Node *p_node) { #ifdef TOOLS_ENABLED edited_scene_root = p_node; @@ -1330,18 +1104,6 @@ void SceneTree::add_current_scene(Node *p_current) { root->add_child(p_current); } -void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) { - - emit_signal("files_dropped", p_files, p_from_screen); - MainLoop::drop_files(p_files, p_from_screen); -} - -void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) { - - emit_signal("global_menu_action", p_id, p_meta); - MainLoop::global_menu_action(p_id, p_meta); -} - Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) { Ref<SceneTreeTimer> stt; @@ -1469,8 +1231,6 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); - ClassDB::bind_method(D_METHOD("set_input_as_handled"), &SceneTree::set_input_as_handled); - ClassDB::bind_method(D_METHOD("is_input_handled"), &SceneTree::is_input_handled); ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true)); @@ -1478,8 +1238,6 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize", "shrink"), &SceneTree::set_screen_stretch, DEFVAL(1)); - ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); MethodInfo mi; @@ -1529,15 +1287,11 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); - ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling); - ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); @@ -1549,14 +1303,12 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("screen_resized")); ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("idle_frame")); ADD_SIGNAL(MethodInfo("physics_frame")); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); - ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta"))); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("connected_to_server")); @@ -1567,16 +1319,6 @@ void SceneTree::_bind_methods() { BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE); BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME); BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE); - - BIND_ENUM_CONSTANT(STRETCH_MODE_DISABLED); - BIND_ENUM_CONSTANT(STRETCH_MODE_2D); - BIND_ENUM_CONSTANT(STRETCH_MODE_VIEWPORT); - - BIND_ENUM_CONSTANT(STRETCH_ASPECT_IGNORE); - BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP); - BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_WIDTH); - BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_HEIGHT); - BIND_ENUM_CONSTANT(STRETCH_ASPECT_EXPAND); } SceneTree *SceneTree::singleton = NULL; @@ -1596,19 +1338,6 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) { idle_callbacks[idle_callback_count++] = p_callback; } -void SceneTree::set_use_font_oversampling(bool p_oversampling) { - - if (use_font_oversampling == p_oversampling) - return; - - use_font_oversampling = p_oversampling; - _update_root_rect(); -} - -bool SceneTree::is_using_font_oversampling() const { - return use_font_oversampling; -} - void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { if (p_function == "change_scene") { @@ -1648,7 +1377,6 @@ SceneTree::SceneTree() { accept_quit = true; quit_on_go_back = true; initialized = false; - use_font_oversampling = false; #ifdef DEBUG_ENABLED debug_collisions_hint = false; debug_navigation_hint = false; @@ -1665,7 +1393,6 @@ SceneTree::SceneTree() { idle_process_time = 1; root = NULL; - input_handled = false; pause = false; current_frame = 0; current_event = 0; @@ -1680,9 +1407,8 @@ SceneTree::SceneTree() { //create with mainloop - root = memnew(Viewport); + root = memnew(Window); root->set_name("root"); - root->set_handle_input_locally(false); if (!root->get_world().is_valid()) root->set_world(Ref<World>(memnew(World))); @@ -1730,15 +1456,12 @@ SceneTree::SceneTree() { } } - stretch_mode = STRETCH_MODE_DISABLED; - stretch_aspect = STRETCH_ASPECT_IGNORE; - stretch_shrink = 1; - - last_screen_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); - _update_root_rect(); - root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true)); + root->connect("close_requested", callable_mp(this, &SceneTree::_main_window_close)); + root->connect("go_back_requested", callable_mp(this, &SceneTree::_main_window_go_back)); + root->connect("focus_entered", callable_mp(this, &SceneTree::_main_window_focus_in)); + #ifdef TOOLS_ENABLED edited_scene_root = NULL; #endif diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 2f805d074f..e6b2575f98 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -39,9 +39,11 @@ #include "scene/resources/world.h" #include "scene/resources/world_2d.h" +#undef Window + class PackedScene; class Node; -class Viewport; +class Window; class Material; class Mesh; class SceneDebugger; @@ -76,22 +78,6 @@ class SceneTree : public MainLoop { public: typedef void (*IdleCallback)(); - enum StretchMode { - - STRETCH_MODE_DISABLED, - STRETCH_MODE_2D, - STRETCH_MODE_VIEWPORT, - }; - - enum StretchAspect { - - STRETCH_ASPECT_IGNORE, - STRETCH_ASPECT_KEEP, - STRETCH_ASPECT_KEEP_WIDTH, - STRETCH_ASPECT_KEEP_HEIGHT, - STRETCH_ASPECT_EXPAND, - }; - private: struct Group { @@ -101,7 +87,7 @@ private: Group() { changed = false; }; }; - Viewport *root; + Window *root; uint64_t tree_version; float physics_process_time; @@ -119,15 +105,12 @@ private: Map<StringName, Group> group_map; bool _quit; bool initialized; - bool input_handled; - Size2 last_screen_size; StringName tree_changed_name; StringName node_added_name; StringName node_removed_name; StringName node_renamed_name; - bool use_font_oversampling; int64_t current_frame; int64_t current_event; int node_count; @@ -147,14 +130,6 @@ private: int call_lock; Set<Node *> call_skip; //skip erased nodes - StretchMode stretch_mode; - StretchAspect stretch_aspect; - Size2i stretch_min; - real_t stretch_shrink; - - void _update_font_oversampling(float p_ratio); - void _update_root_rect(); - List<ObjectID> delete_queue; Map<UGCall, Vector<Variant>> unique_group_calls; @@ -208,7 +183,6 @@ private: void make_group_changed(const StringName &p_group); void _notify_group_pause(const StringName &p_group, int p_notification); - void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input); Variant _call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -232,6 +206,13 @@ private: static int idle_callback_count; void _call_idle_callbacks(); + void _main_window_focus_in(); + void _main_window_close(); + void _main_window_go_back(); + + //used by viewport + void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport); + protected: void _notification(int p_notification); static void _bind_methods(); @@ -249,7 +230,7 @@ public: GROUP_CALL_MULTILEVEL = 8, }; - _FORCE_INLINE_ Viewport *get_root() const { return root; } + _FORCE_INLINE_ Window *get_root() const { return root; } void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); @@ -261,8 +242,6 @@ public: void flush_transform_notifications(); - virtual void input_text(const String &p_text); - virtual void input_event(const Ref<InputEvent> &p_event); virtual void init(); virtual bool iteration(float p_time); @@ -275,8 +254,6 @@ public: void quit(int p_exit_code = -1); - void set_input_as_handled(); - bool is_input_handled(); _FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; } _FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; } @@ -335,11 +312,6 @@ public: void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list); bool has_group(const StringName &p_identifier) const; - void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink = 1); - - void set_use_font_oversampling(bool p_oversampling); - bool is_using_font_oversampling() const; - //void change_scene(const String& p_path); //Node *get_loaded_scene(); @@ -359,8 +331,6 @@ public: static SceneTree *get_singleton() { return singleton; } - void drop_files(const Vector<String> &p_files, int p_from_screen = 0); - void global_menu_action(const Variant &p_id, const Variant &p_meta); void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; //network API @@ -388,8 +358,6 @@ public: ~SceneTree(); }; -VARIANT_ENUM_CAST(SceneTree::StretchMode); -VARIANT_ENUM_CAST(SceneTree::StretchAspect); VARIANT_ENUM_CAST(SceneTree::GroupCallFlags); #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 8ef3bdd04e..e49674663a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" -#include "core/os/input.h" +#include "core/input/input_filter.h" #include "core/os/os.h" #include "core/project_settings.h" #include "scene/2d/collision_object_2d.h" @@ -49,8 +49,10 @@ #include "scene/gui/popup_menu.h" #include "scene/main/canvas_layer.h" #include "scene/main/timer.h" +#include "scene/main/window.h" #include "scene/resources/mesh.h" #include "scene/scene_string_names.h" +#include "servers/display_server.h" #include "servers/physics_2d_server.h" void ViewportTexture::setup_local_to_scene() { @@ -141,7 +143,7 @@ void ViewportTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene); ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "SubViewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); } ViewportTexture::ViewportTexture() { @@ -166,9 +168,9 @@ ViewportTexture::~ViewportTexture() { ///////////////////////////////////// -class TooltipPanel : public PanelContainer { +class TooltipPanel : public PopupPanel { - GDCLASS(TooltipPanel, PanelContainer); + GDCLASS(TooltipPanel, PopupPanel); public: TooltipPanel(){}; @@ -184,39 +186,25 @@ public: Viewport::GUI::GUI() { + embed_subwindows_hint = false; + embedding_subwindows = false; + dragging = false; mouse_focus = NULL; + forced_mouse_focus = false; mouse_click_grabber = NULL; mouse_focus_mask = 0; key_focus = NULL; mouse_over = NULL; + drag_mouse_over = NULL; tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; - subwindow_visibility_dirty = false; - subwindow_order_dirty = false; } ///////////////////////////////////// -void Viewport::_update_stretch_transform() { - - if (size_override_stretch && size_override) { - - stretch_transform = Transform2D(); - Size2 scale = size / (size_override_size + size_override_margin * 2); - stretch_transform.scale(scale); - stretch_transform.elements[2] = size_override_margin * scale; - - } else { - - stretch_transform = Transform2D(); - } - - _update_global_transform(); -} - void Viewport::update_worlds() { if (!is_inside_tree()) @@ -249,6 +237,191 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera * physics_last_id = id; } +void Viewport::_sub_window_update_order() { + + for (int i = 0; i < gui.sub_windows.size(); i++) { + VS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i); + } +} + +void Viewport::_sub_window_register(Window *p_window) { + + ERR_FAIL_COND(!is_inside_tree()); + for (int i = 0; i < gui.sub_windows.size(); i++) { + ERR_FAIL_COND(gui.sub_windows[i].window == p_window); + } + + if (gui.sub_windows.size() == 0) { + subwindow_canvas = VS::get_singleton()->canvas_create(); + VS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas); + VS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0); + } + SubWindow sw; + sw.canvas_item = VS::get_singleton()->canvas_item_create(); + VS::get_singleton()->canvas_item_set_parent(sw.canvas_item, subwindow_canvas); + sw.window = p_window; + gui.sub_windows.push_back(sw); + + _sub_window_grab_focus(p_window); + + VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, viewport); +} + +void Viewport::_sub_window_update(Window *p_window) { + + int index = -1; + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + index = i; + break; + } + } + + ERR_FAIL_COND(index == -1); + + const SubWindow &sw = gui.sub_windows[index]; + + Transform2D pos; + pos.set_origin(p_window->get_position()); + VS::get_singleton()->canvas_item_clear(sw.canvas_item); + Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size()); + + if (!p_window->get_flag(Window::FLAG_BORDERLESS)) { + Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window"); + panel->draw(sw.canvas_item, r); + + // Draw the title bar text. + Ref<Font> title_font = p_window->get_theme_font("title_font"); + Color title_color = p_window->get_theme_color("title_color"); + int title_height = p_window->get_theme_constant("title_height"); + int font_height = title_font->get_height() - title_font->get_descent() * 2; + int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2; + int y = (-title_height + font_height) / 2; + + int close_h_ofs = p_window->get_theme_constant("close_h_ofs"); + int close_v_ofs = p_window->get_theme_constant("close_v_ofs"); + + title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs); + + bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside; + + Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close"); + close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs)); + } + + VS::get_singleton()->canvas_item_add_texture_rect(sw.canvas_item, r, sw.window->get_texture()->get_rid()); +} + +void Viewport::_sub_window_grab_focus(Window *p_window) { + + if (p_window == nullptr) { + //release current focus + if (gui.subwindow_focused) { + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + gui.subwindow_focused = nullptr; + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + } + + Window *this_window = Object::cast_to<Window>(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } + + return; + } + + int index = -1; + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + index = i; + break; + } + } + + ERR_FAIL_COND(index == -1); + + if (p_window->get_flag(Window::FLAG_NO_FOCUS)) { + //can only move to foreground, but no focus granted + SubWindow sw = gui.sub_windows[index]; + gui.sub_windows.remove(index); + gui.sub_windows.push_back(sw); + index = gui.sub_windows.size() - 1; + _sub_window_update_order(); + return; //i guess not... + } + + if (gui.subwindow_focused) { + if (gui.subwindow_focused == p_window) { + return; //nothing to do + } + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + } else { + Window *this_window = Object::cast_to<Window>(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + } + } + + Window *old_focus = gui.subwindow_focused; + + gui.subwindow_focused = p_window; + + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + + { //move to foreground + SubWindow sw = gui.sub_windows[index]; + gui.sub_windows.remove(index); + gui.sub_windows.push_back(sw); + index = gui.sub_windows.size() - 1; + _sub_window_update_order(); + } + + if (old_focus) { + _sub_window_update(old_focus); + } + + _sub_window_update(p_window); +} + +void Viewport::_sub_window_remove(Window *p_window) { + + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + VS::get_singleton()->free(gui.sub_windows[i].canvas_item); + gui.sub_windows.remove(i); + break; + } + } + + if (gui.sub_windows.size() == 0) { + VS::get_singleton()->free(subwindow_canvas); + subwindow_canvas = RID(); + } + + if (gui.subwindow_focused == p_window) { + Window *parent_visible = p_window->get_parent_visible_window(); + + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + + if (parent_visible && parent_visible != this) { + + gui.subwindow_focused = parent_visible; + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } else { + gui.subwindow_focused = nullptr; + Window *this_window = Object::cast_to<Window>(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } + } + } + + VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID()); +} + void Viewport::_own_world_changed() { ERR_FAIL_COND(world.is_null()); ERR_FAIL_COND(own_world.is_null()); @@ -276,6 +449,8 @@ void Viewport::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + gui.embedding_subwindows = gui.embed_subwindows_hint; + if (get_parent()) { parent = get_parent()->get_viewport(); VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid()); @@ -310,7 +485,6 @@ void Viewport::_notification(int p_what) { //VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true); } - VS::get_singleton()->viewport_set_active(viewport, true); } break; case NOTIFICATION_READY: { #ifndef _3D_DISABLED @@ -371,6 +545,7 @@ void Viewport::_notification(int p_what) { remove_from_group("_viewports"); VS::get_singleton()->viewport_set_active(viewport, false); + VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, RID()); } break; case NOTIFICATION_INTERNAL_PROCESS: { @@ -408,7 +583,7 @@ void Viewport::_notification(int p_what) { VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count); } - if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) { + if (physics_object_picking && (to_screen_rect == Rect2i() || InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED)) { #ifndef _3D_DISABLED Vector2 last_pos(1e20, 1e20); @@ -433,6 +608,7 @@ void Viewport::_notification(int p_what) { if (!has_mouse_event) { Ref<InputEventMouseMotion> mm; mm.instance(); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); mm->set_global_position(physics_last_mousepos); mm->set_position(physics_last_mousepos); @@ -680,13 +856,12 @@ void Viewport::_notification(int p_what) { } } break; - case SceneTree::NOTIFICATION_WM_MOUSE_EXIT: - case SceneTree::NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_MOUSE_EXIT: + case NOTIFICATION_WM_FOCUS_OUT: { _drop_physics_mouseover(); - if (gui.mouse_focus) { - //if mouse is being pressed, send a release event + if (gui.mouse_focus && !gui.forced_mouse_focus) { _drop_mouse_focus(); } } break; @@ -698,16 +873,6 @@ RID Viewport::get_viewport_rid() const { return viewport; } -void Viewport::set_use_arvr(bool p_use_arvr) { - arvr = p_use_arvr; - - VS::get_singleton()->viewport_set_use_arvr(viewport, arvr); -} - -bool Viewport::use_arvr() { - return arvr; -} - void Viewport::update_canvas_items() { if (!is_inside_tree()) return; @@ -715,40 +880,52 @@ void Viewport::update_canvas_items() { _update_canvas_items(this); } -void Viewport::set_size(const Size2 &p_size) { +void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) { - if (size == p_size.floor()) + if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_override == size_override && to_screen_rect != p_to_screen_rect) return; - size = p_size.floor(); - VS::get_singleton()->viewport_set_size(viewport, size.width, size.height); + size = p_size; + size_allocated = p_allocated; + size_override = p_size_override; + stretch_transform = p_stretch_transform; + to_screen_rect = p_to_screen_rect; + + if (p_allocated) { + VS::get_singleton()->viewport_set_size(viewport, size.width, size.height); + } else { + VS::get_singleton()->viewport_set_size(viewport, 0, 0); + } + _update_global_transform(); - _update_stretch_transform(); + update_canvas_items(); emit_signal("size_changed"); } +Size2i Viewport::_get_size() const { + return size; +} +bool Viewport::_is_size_allocated() const { + return size_allocated; +} + Rect2 Viewport::get_visible_rect() const { Rect2 r; if (size == Size2()) { - r = Rect2(Point2(), OS::get_singleton()->get_window_size()); + r = Rect2(Point2(), DisplayServer::get_singleton()->window_get_size()); } else { r = Rect2(Point2(), size); } - if (size_override) { - r.size = size_override_size; + if (size_override != Size2i()) { + r.size = size_override; } return r; } -Size2 Viewport::get_size() const { - - return size; -} - void Viewport::_update_listener() { /* if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree()))) { @@ -943,7 +1120,9 @@ void Viewport::_camera_set(Camera *p_camera) { if (camera) { camera->notification(Camera::NOTIFICATION_LOST_CURRENT); } + camera = p_camera; + if (!camera_override) { if (camera) VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); @@ -1278,70 +1457,11 @@ void Viewport::_update_canvas_items(Node *p_node) { } } -void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) { - - if (size_override == p_enable && p_size == size_override_size) - return; - - size_override = p_enable; - if (p_size.x >= 0 || p_size.y >= 0) { - size_override_size = p_size; - } - size_override_margin = p_margin; - - _update_stretch_transform(); - emit_signal("size_changed"); -} - -Size2 Viewport::get_size_override() const { - - return size_override_size; -} -bool Viewport::is_size_override_enabled() const { - - return size_override; -} -void Viewport::set_size_override_stretch(bool p_enable) { - - if (p_enable == size_override_stretch) - return; - - size_override_stretch = p_enable; - - _update_stretch_transform(); -} - -bool Viewport::is_size_override_stretch_enabled() const { - - return size_override_stretch; -} - -void Viewport::set_update_mode(UpdateMode p_mode) { - - update_mode = p_mode; - VS::get_singleton()->viewport_set_update_mode(viewport, VS::ViewportUpdateMode(p_mode)); -} -Viewport::UpdateMode Viewport::get_update_mode() const { - - return update_mode; -} - Ref<ViewportTexture> Viewport::get_texture() const { return default_texture; } -void Viewport::set_clear_mode(ClearMode p_mode) { - - clear_mode = p_mode; - VS::get_singleton()->viewport_set_clear_mode(viewport, VS::ViewportClearMode(p_mode)); -} - -Viewport::ClearMode Viewport::get_clear_mode() const { - - return clear_mode; -} - void Viewport::set_shadow_atlas_size(int p_size) { if (shadow_atlas_size == p_size) @@ -1379,7 +1499,7 @@ Transform2D Viewport::_get_input_pre_xform() const { Transform2D pre_xf; - if (to_screen_rect != Rect2()) { + if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) { pre_xf.elements[2] = -to_screen_rect.position; pre_xf.scale(size / to_screen_rect.size); @@ -1388,118 +1508,22 @@ Transform2D Viewport::_get_input_pre_xform() const { return pre_xf; } -Vector2 Viewport::_get_window_offset() const { - - if (get_parent() && get_parent()->has_method("get_global_position")) { - return get_parent()->call("get_global_position"); - } - return Vector2(); -} - Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) { - Vector2 vp_ofs = _get_window_offset(); Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform(); - return ev->xformed_by(ai, -vp_ofs); -} - -void Viewport::_vp_input_text(const String &p_text) { - - if (gui.key_focus) { - gui.key_focus->call("set_text", p_text); - } -} - -void Viewport::_vp_input(const Ref<InputEvent> &p_ev) { - - if (disable_input) - return; - -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { - return; - } -#endif - - if (to_screen_rect == Rect2()) - return; //if render target, can't get input events - - //this one handles system input, p_ev are in system coordinates - //they are converted to viewport coordinates - - Ref<InputEvent> ev = _make_input_local(p_ev); - input(ev); -} - -void Viewport::_vp_unhandled_input(const Ref<InputEvent> &p_ev) { - - if (disable_input) - return; -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { - return; - } -#endif - - /* - if (parent_control && !parent_control->is_visible_in_tree()) - return; - */ - - if (to_screen_rect == Rect2()) - return; //if render target, can't get input events - - //this one handles system input, p_ev are in system coordinates - //they are converted to viewport coordinates - - Ref<InputEvent> ev = _make_input_local(p_ev); - unhandled_input(ev); + return ev->xformed_by(ai); } Vector2 Viewport::get_mouse_position() const { - return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(Input::get_singleton()->get_mouse_position() - _get_window_offset()); + return gui.last_mouse_pos; } void Viewport::warp_mouse(const Vector2 &p_pos) { Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos); - Input::get_singleton()->warp_mouse_position(gpos); -} - -void Viewport::_gui_prepare_subwindows() { - - if (gui.subwindow_visibility_dirty) { - - gui.subwindows.clear(); - for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) { - if (E->get()->is_visible_in_tree()) { - gui.subwindows.push_back(E->get()); - } - } - - gui.subwindow_visibility_dirty = false; - gui.subwindow_order_dirty = true; - } - - _gui_sort_subwindows(); -} - -void Viewport::_gui_sort_subwindows() { - - if (!gui.subwindow_order_dirty) - return; - - gui.modal_stack.sort_custom<Control::CComparator>(); - gui.subwindows.sort_custom<Control::CComparator>(); - - gui.subwindow_order_dirty = false; -} - -void Viewport::_gui_sort_modal_stack() { - - gui.modal_stack.sort_custom<Control::CComparator>(); + InputFilter::get_singleton()->warp_mouse_position(gpos); } void Viewport::_gui_sort_roots() { @@ -1575,47 +1599,49 @@ void Viewport::_gui_show_tooltip() { Control *rp = which; - gui.tooltip_popup = which->make_custom_tooltip(tooltip); - - if (!gui.tooltip_popup) { - gui.tooltip_popup = memnew(TooltipPanel); + Control *base_tooltip = which->make_custom_tooltip(tooltip); + if (!base_tooltip) { gui.tooltip_label = memnew(TooltipLabel); - gui.tooltip_popup->add_child(gui.tooltip_label); - - Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel"); - - gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); gui.tooltip_label->set_text(tooltip); + base_tooltip = gui.tooltip_label; } + base_tooltip->set_anchors_and_margins_preset(Control::PRESET_WIDE); + + TooltipPanel *panel = memnew(TooltipPanel); + panel->set_transient(false); + panel->set_flag(Window::FLAG_NO_FOCUS, true); + panel->set_wrap_controls(true); + panel->add_child(base_tooltip); + + gui.tooltip_popup = panel; + rp->add_child(gui.tooltip_popup); - gui.tooltip_popup->force_parent_owned(); - gui.tooltip_popup->set_as_toplevel(true); - if (gui.tooltip) // Avoids crash when rapidly switching controls. - gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale()); + + //if (gui.tooltip) // Avoids crash when rapidly switching controls. + // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale()); Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset"); - Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size()); - Rect2 vr = gui.tooltip_popup->get_viewport_rect(); - if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x) - r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x; - else if (r.position.x < 0) - r.position.x = 0; - - if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y) - r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y; - else if (r.position.y < 0) - r.position.y = 0; - - gui.tooltip_popup->set_global_position(r.position); + Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size()); + + Rect2i vr = gui.tooltip_popup->get_parent_visible_window()->get_usable_parent_rect(); + + if (r.size.x + r.position.x > vr.size.x + vr.position.x) + r.position.x = vr.position.x + vr.size.x - r.size.x; + else if (r.position.x < vr.position.x) + r.position.x = vr.position.x; + + if (r.size.y + r.position.y > vr.size.y + vr.position.y) + r.position.y = vr.position.y + vr.size.y - r.size.y; + else if (r.position.y < vr.position.y) + r.position.y = vr.position.y; + + gui.tooltip_popup->set_position(r.position); gui.tooltip_popup->set_size(r.size); - gui.tooltip_popup->raise(); gui.tooltip_popup->show(); + gui.tooltip_popup->child_controls_changed(); } void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) { @@ -1704,26 +1730,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) { } Control *Viewport::_gui_find_control(const Point2 &p_global) { - _gui_prepare_subwindows(); - - for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) { - - Control *sw = E->get(); - if (!sw->is_visible_in_tree()) - continue; - - Transform2D xform; - CanvasItem *pci = sw->get_parent_item(); - if (pci) - xform = pci->get_global_transform_with_canvas(); - else - xform = sw->get_canvas_transform(); - - Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform); - if (ret) - return ret; - } - + //aca va subwindows _gui_sort_roots(); for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) { @@ -1752,8 +1759,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ if (Object::cast_to<Viewport>(p_node)) return NULL; - //subwindows first!! - if (!p_node->is_visible()) { //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform); return NULL; //canvas item hidden, discard @@ -1770,9 +1775,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ for (int i = p_node->get_child_count() - 1; i >= 0; i--) { - if (p_node == gui.tooltip_popup) - continue; - CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i)); if (!ci || ci->is_set_as_toplevel()) continue; @@ -1858,39 +1860,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool is_handled = false; - _gui_sort_modal_stack(); - while (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos); - if (!top->has_point(pos2)) { - - if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) { - //cancel event, sorry, modal exclusive EATS UP ALL - //alternative, you can't pop out a window the same frame it was made modal (fixes many issues) - set_input_as_handled(); - - return; // no one gets the event if exclusive NO ONE - } - - if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) { - //cancel scroll wheel events, only clicks should trigger focus changes. - set_input_as_handled(); - return; - } - - top->notification(Control::NOTIFICATION_MODAL_CLOSE); - top->_modal_stack_remove(); - top->hide(); - - if (!top->pass_on_modal_close_click()) { - is_handled = true; - } - } else { - break; - } - } - if (is_handled) { set_input_as_handled(); return; @@ -1992,11 +1961,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { - if (gui.mouse_over) { - Size2 pos = mpos; - pos = gui.focus_inv_xform.xform(pos); - - _gui_drop(gui.mouse_over, pos, false); + if (gui.drag_mouse_over) { + _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); } if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) { @@ -2006,6 +1972,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_data = Variant(); gui.dragging = false; + gui.drag_mouse_over = nullptr; _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); //change mouse accordingly } @@ -2029,6 +1996,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise if (gui.mouse_focus_mask == 0) { gui.mouse_focus = NULL; + gui.forced_mouse_focus = false; } if (mouse_focus && mouse_focus->can_process()) { @@ -2074,6 +2042,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.drag_data.get_type() != Variant::NIL) { gui.mouse_focus = NULL; + gui.forced_mouse_focus = false; gui.mouse_focus_mask = 0; break; } else { @@ -2113,45 +2082,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { over = _gui_find_control(mpos); } - if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - - if (over != top && !top->is_a_parent_of(over)) { - - PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top); - MenuButton *popup_menu_parent = NULL; - MenuButton *menu_button = Object::cast_to<MenuButton>(over); - - if (popup_menu) { - popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent()); - if (!popup_menu_parent) { - // Go through the parents to see if there's a MenuButton at the end. - while (Object::cast_to<PopupMenu>(popup_menu->get_parent())) { - popup_menu = Object::cast_to<PopupMenu>(popup_menu->get_parent()); - } - popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent()); - } - } - - // If the mouse is over a menu button, this menu will open automatically - // if there is already a pop-up menu open at the same hierarchical level. - if (popup_menu_parent && menu_button && popup_menu_parent->is_switch_on_hover() && - !menu_button->is_disabled() && menu_button->is_switch_on_hover() && - (popup_menu_parent->get_parent()->is_a_parent_of(menu_button) || - menu_button->get_parent()->is_a_parent_of(popup_menu))) { - - popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE); - popup_menu->_modal_stack_remove(); - popup_menu->hide(); - - menu_button->pressed(); - } else { - over = NULL; //nothing can be found outside the modal stack - } - } - } - if (over != gui.mouse_over) { if (gui.mouse_over) { @@ -2167,103 +2097,195 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.mouse_over = over; - if (gui.drag_preview) { - gui.drag_preview->set_position(mpos); - } + DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)InputFilter::get_singleton()->get_default_cursor_shape(); - if (!over) { - OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape()); - return; - } + if (over) { - Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse(); - Size2 pos = localizer.xform(mpos); - Vector2 speed = localizer.basis_xform(mm->get_speed()); - Vector2 rel = localizer.basis_xform(mm->get_relative()); + Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse(); + Size2 pos = localizer.xform(mpos); + Vector2 speed = localizer.basis_xform(mm->get_speed()); + Vector2 rel = localizer.basis_xform(mm->get_relative()); - mm = mm->xformed_by(Transform2D()); //make a copy + mm = mm->xformed_by(Transform2D()); //make a copy - mm->set_global_position(mpos); - mm->set_speed(speed); - mm->set_relative(rel); + mm->set_global_position(mpos); + mm->set_speed(speed); + mm->set_relative(rel); - if (mm->get_button_mask() == 0) { - //nothing pressed + if (mm->get_button_mask() == 0) { + //nothing pressed - bool can_tooltip = true; + bool can_tooltip = true; - if (!gui.modal_stack.empty()) { - if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over)) - can_tooltip = false; - } + bool is_tooltip_shown = false; + + if (gui.tooltip_popup) { + if (can_tooltip && gui.tooltip) { + String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos)); - bool is_tooltip_shown = false; + if (tooltip.length() == 0) + _gui_cancel_tooltip(); + else if (gui.tooltip_label) { + if (tooltip == gui.tooltip_label->get_text()) { + is_tooltip_shown = true; + } + } else { - if (gui.tooltip_popup) { - if (can_tooltip && gui.tooltip) { - String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos)); + Variant t = gui.tooltip_popup->call("get_tooltip_text"); - if (tooltip.length() == 0) - _gui_cancel_tooltip(); - else if (gui.tooltip_label) { - if (tooltip == gui.tooltip_label->get_text()) { - is_tooltip_shown = true; + if (t.get_type() == Variant::STRING) { + if (tooltip == String(t)) { + is_tooltip_shown = true; + } + } else { + is_tooltip_shown = true; //well, nothing to compare against, likely using custom control, so if it changes there is nothing we can do + } } - } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) { - is_tooltip_shown = true; - } - } else - _gui_cancel_tooltip(); + } else + _gui_cancel_tooltip(); + } + + if (can_tooltip && !is_tooltip_shown) { + + gui.tooltip = over; + gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos); + gui.tooltip_timer = gui.tooltip_delay; + } } - if (can_tooltip && !is_tooltip_shown) { + //pos = gui.focus_inv_xform.xform(pos); - gui.tooltip = over; - gui.tooltip_pos = mpos; //(parent_xform * get_transform()).affine_inverse().xform(pos); - gui.tooltip_timer = gui.tooltip_delay; + mm->set_position(pos); + + Control::CursorShape cursor_shape = Control::CURSOR_ARROW; + { + Control *c = over; + Vector2 cpos = pos; + while (c) { + cursor_shape = c->get_cursor_shape(cpos); + cpos = c->get_transform().xform(cpos); + if (cursor_shape != Control::CURSOR_ARROW) + break; + if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP) + break; + if (c->is_set_as_toplevel()) + break; + c = c->get_parent_control(); + } } + + ds_cursor_shape = (DisplayServer::CursorShape)cursor_shape; + + if (over && over->can_process()) { + _gui_call_input(over, mm); + } + + set_input_as_handled(); } - //pos = gui.focus_inv_xform.xform(pos); + if (gui.drag_data.get_type() != Variant::NIL) { + //handle dragandrop - mm->set_position(pos); + if (gui.drag_preview) { + gui.drag_preview->set_position(mpos); + } - Control::CursorShape cursor_shape = Control::CURSOR_ARROW; - { - Control *c = over; - Vector2 cpos = pos; - while (c) { - cursor_shape = c->get_cursor_shape(cpos); - cpos = c->get_transform().xform(cpos); - if (cursor_shape != Control::CURSOR_ARROW) - break; - if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP) - break; - if (c->is_set_as_toplevel()) - break; - c = c->get_parent_control(); + gui.drag_mouse_over = over; + gui.drag_mouse_over_pos = Vector2(); + + //find the window this is above of + + //see if there is an embedder + Viewport *embedder = nullptr; + Vector2 viewport_pos; + + if (is_embedding_subwindows()) { + embedder = this; + viewport_pos = mpos; + } else { + //not an embeder, but may be a subwindow of an embedder + Window *w = Object::cast_to<Window>(this); + if (w) { + if (w->is_embedded()) { + embedder = w->_get_embedder(); + + Transform2D ai = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse(); + + viewport_pos = ai.xform(mpos) + w->get_position(); //to parent coords + } + } } - } - OS::get_singleton()->set_cursor_shape((OS::CursorShape)cursor_shape); + Viewport *viewport_under = nullptr; - if (over && over->can_process()) { - _gui_call_input(over, mm); - } + if (embedder) { + //use embedder logic - set_input_as_handled(); + for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) { + Window *sw = embedder->gui.sub_windows[i].window; + Rect2 swrect = Rect2i(sw->get_position(), sw->get_size()); + if (!sw->get_flag(Window::FLAG_BORDERLESS)) { + int title_height = sw->get_theme_constant("title_height"); + swrect.position.y -= title_height; + swrect.size.y += title_height; + } - if (gui.drag_data.get_type() != Variant::NIL && mm->get_button_mask() & BUTTON_MASK_LEFT) { + if (swrect.has_point(viewport_pos)) { + viewport_under = sw; + viewport_pos -= sw->get_position(); + } + } - bool can_drop = _gui_drop(over, pos, true); + if (!viewport_under) { + //not in a subwindow, likely in embedder + viewport_under = embedder; + } + } else { + //use displayserver logic + Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); + + DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos); + + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id); + + if (object_under != ObjectID()) { //fetch window + Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under)); + if (w) { + viewport_under = w; + viewport_pos = screen_mouse_pos - w->get_position(); + } + } + } + } + + if (viewport_under) { + Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform()); + viewport_pos = ai.xform(viewport_pos); + //find control under at pos + gui.drag_mouse_over = viewport_under->_gui_find_control(viewport_pos); + if (gui.drag_mouse_over) { + Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse(); + gui.drag_mouse_over_pos = localizer.xform(viewport_pos); + + if (mm->get_button_mask() & BUTTON_MASK_LEFT) { + + bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true); + + if (!can_drop) { + ds_cursor_shape = DisplayServer::CURSOR_FORBIDDEN; + } else { + ds_cursor_shape = DisplayServer::CURSOR_CAN_DROP; + } + } + } - if (!can_drop) { - OS::get_singleton()->set_cursor_shape(OS::CURSOR_FORBIDDEN); } else { - OS::get_singleton()->set_cursor_shape(OS::CURSOR_CAN_DROP); + gui.drag_mouse_over = nullptr; } - //change mouse accordingly i guess } + + DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape); } Ref<InputEventScreenTouch> touch_event = p_event; @@ -2275,14 +2297,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = _gui_find_control(pos); if (over) { - if (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - if (over != top && !top->is_a_parent_of(over)) { - - return; - } - } if (over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); //make a copy @@ -2348,14 +2362,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (over) { - if (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - if (over != top && !top->is_a_parent_of(over)) { - - return; - } - } if (over->can_process()) { Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse(); @@ -2399,21 +2405,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) { - - _gui_sort_modal_stack(); - Control *top = gui.modal_stack.back()->get(); - if (!top->data.modal_exclusive) { - - top->notification(Control::NOTIFICATION_MODAL_CLOSE); - top->_modal_stack_remove(); - top->hide(); - // Close modal, set input as handled - set_input_as_handled(); - return; - } - } - Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm //keyboard focus @@ -2426,7 +2417,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (from && p_event->is_pressed()) { Control *next = NULL; - Input *input = Input::get_singleton(); + InputFilter *input = InputFilter::get_singleton(); if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) { @@ -2472,61 +2463,10 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) { return gui.roots.push_back(p_control); } -List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) { - - p_control->connect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed)); - - if (p_control->is_visible_in_tree()) { - gui.subwindow_order_dirty = true; - gui.subwindows.push_back(p_control); - } - - return gui.all_known_subwindows.push_back(p_control); -} - -void Viewport::_gui_set_subwindow_order_dirty() { - gui.subwindow_order_dirty = true; -} - void Viewport::_gui_set_root_order_dirty() { gui.roots_order_dirty = true; } -void Viewport::_gui_remove_modal_control(List<Control *>::Element *MI) { - - gui.modal_stack.erase(MI); -} - -void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) { - - //transfer the focus stack to the next - - List<Control *>::Element *next = MI->next(); - - gui.modal_stack.erase(MI); - - if (p_prev_focus_owner.is_valid()) { - - // for previous window in stack, pass the focus so it feels more - // natural - - if (!next) { //top of stack - - Object *pfo = ObjectDB::get_instance(p_prev_focus_owner); - Control *pfoc = Object::cast_to<Control>(pfo); - if (!pfoc) - return; - - if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree()) - return; - pfoc->grab_focus(); - } else { - - next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner); - } - } -} - void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) { ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value."); @@ -2563,21 +2503,6 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) { gui.roots.erase(RI); } -void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) { - - ERR_FAIL_COND(!SI); - - Control *control = SI->get(); - - control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed)); - - List<Control *>::Element *E = gui.subwindows.find(control); - if (E) - gui.subwindows.erase(E); - - gui.all_known_subwindows.erase(SI); -} - void Viewport::_gui_unfocus_control(Control *p_control) { if (gui.key_focus == p_control) { @@ -2605,6 +2530,8 @@ void Viewport::_gui_hid_control(Control *p_control) { _gui_remove_focus(); if (gui.mouse_over == p_control) gui.mouse_over = NULL; + if (gui.drag_mouse_over == p_control) + gui.drag_mouse_over = NULL; if (gui.tooltip == p_control) _gui_cancel_tooltip(); } @@ -2613,6 +2540,7 @@ void Viewport::_gui_remove_control(Control *p_control) { if (gui.mouse_focus == p_control) { gui.mouse_focus = NULL; + gui.forced_mouse_focus = false; gui.mouse_focus_mask = 0; } if (gui.last_mouse_focus == p_control) { @@ -2622,11 +2550,10 @@ void Viewport::_gui_remove_control(Control *p_control) { gui.key_focus = NULL; if (gui.mouse_over == p_control) gui.mouse_over = NULL; + if (gui.drag_mouse_over == p_control) + gui.drag_mouse_over = NULL; if (gui.tooltip == p_control) gui.tooltip = NULL; - if (gui.tooltip_popup == p_control) { - _gui_cancel_tooltip(); - } } void Viewport::_gui_remove_focus() { @@ -2638,11 +2565,6 @@ void Viewport::_gui_remove_focus() { } } -bool Viewport::_gui_is_modal_on_top(const Control *p_control) { - - return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control); -} - bool Viewport::_gui_control_has_focus(const Control *p_control) { return gui.key_focus == p_control; @@ -2672,6 +2594,7 @@ void Viewport::_drop_mouse_focus() { Control *c = gui.mouse_focus; int mask = gui.mouse_focus_mask; gui.mouse_focus = NULL; + gui.forced_mouse_focus = false; gui.mouse_focus_mask = 0; for (int i = 0; i < 3; i++) { @@ -2714,22 +2637,6 @@ void Viewport::_drop_physics_mouseover() { #endif } -List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) { - - List<Control *>::Element *node = gui.modal_stack.push_back(p_control); - if (gui.key_focus) - p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id()); - else - p_control->_modal_set_prev_focus_owner(ObjectID()); - - if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) { - - _drop_mouse_focus(); - } - - return node; -} - Control *Viewport::_gui_get_focus_owner() { return gui.key_focus; @@ -2798,44 +2705,390 @@ void Viewport::_post_gui_grab_click_focus() { /////////////////////////////// -void Viewport::input(const Ref<InputEvent> &p_event) { +void Viewport::input_text(const String &p_text) { + + if (gui.subwindow_focused) { + gui.subwindow_focused->input_text(p_text); + return; + } + + if (gui.key_focus) { + gui.key_focus->call("set_text", p_text); + } +} +Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) { + + if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size()); + + int title_height = p_subwindow->get_theme_constant("title_height"); + + r.position.y -= title_height; + r.size.y += title_height; + + if (r.has_point(p_point)) { + return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize + } + + int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0); + int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0); + + int limit = p_subwindow->get_theme_constant("resize_margin"); + + if (ABS(dist_x) > limit) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + if (ABS(dist_y) > limit) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + if (dist_x < 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP_LEFT; + } + + if (dist_x == 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP; + } + + if (dist_x > 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP_RIGHT; + } + + if (dist_x < 0 && dist_y == 0) { + return SUB_WINDOW_RESIZE_LEFT; + } + + if (dist_x > 0 && dist_y == 0) { + return SUB_WINDOW_RESIZE_RIGHT; + } + + if (dist_x < 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM_LEFT; + } + + if (dist_x == 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM; + } + + if (dist_x > 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM_RIGHT; + } + + return SUB_WINDOW_RESIZE_DISABLED; +} +bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { + + if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) { + + ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false); + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { + if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) { + //close window + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST); + } + } + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + if (gui.subwindow_focused != nullptr) { //may have been erased + _sub_window_update(gui.subwindow_focused); + } + } + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + + if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) { + Vector2 diff = mm->get_position() - gui.subwindow_drag_from; + Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size()); + gui.subwindow_focused->_rect_changed_callback(new_rect); + } + if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { + gui.subwindow_drag_close_inside = gui.subwindow_drag_close_rect.has_point(mm->get_position()); + } + if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) { + Vector2i diff = mm->get_position() - gui.subwindow_drag_from; + Size2i min_size = gui.subwindow_focused->get_min_size(); + if (gui.subwindow_focused->is_wrapping_controls()) { + Size2i cms = gui.subwindow_focused->get_contents_minimum_size(); + min_size.x = MAX(cms.x, min_size.x); + min_size.y = MAX(cms.y, min_size.y); + } + min_size.x = MAX(min_size.x, 1); + min_size.y = MAX(min_size.y, 1); + + Rect2i r = gui.subwindow_resize_from_rect; + + Size2i limit = r.size - min_size; + + switch (gui.subwindow_resize_mode) { + case SUB_WINDOW_RESIZE_TOP_LEFT: { + + diff.x = MIN(diff.x, limit.x); + diff.y = MIN(diff.y, limit.y); + r.position += diff; + r.size -= diff; + } break; + case SUB_WINDOW_RESIZE_TOP: { + diff.x = 0; + diff.y = MIN(diff.y, limit.y); + r.position += diff; + r.size -= diff; + } break; + case SUB_WINDOW_RESIZE_TOP_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + diff.y = MIN(diff.y, limit.y); + r.position.y += diff.y; + r.size.y -= diff.y; + r.size.x += diff.x; + } break; + case SUB_WINDOW_RESIZE_LEFT: { + diff.x = MIN(diff.x, limit.x); + diff.y = 0; + r.position += diff; + r.size -= diff; + + } break; + case SUB_WINDOW_RESIZE_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + r.size.x += diff.x; + } break; + case SUB_WINDOW_RESIZE_BOTTOM_LEFT: { + diff.x = MIN(diff.x, limit.x); + diff.y = MAX(diff.y, -limit.y); + r.position.x += diff.x; + r.size.x -= diff.x; + r.size.y += diff.y; + + } break; + case SUB_WINDOW_RESIZE_BOTTOM: { + diff.y = MAX(diff.y, -limit.y); + r.size.y += diff.y; + } break; + case SUB_WINDOW_RESIZE_BOTTOM_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + diff.y = MAX(diff.y, -limit.y); + r.size += diff; + + } break; + default: { + } + } + + gui.subwindow_focused->_rect_changed_callback(r); + } + + if (gui.subwindow_focused) { //may have been erased + _sub_window_update(gui.subwindow_focused); + } + } + + return true; //handled + } + Ref<InputEventMouseButton> mb = p_event; + //if the event is a mouse button, we need to check whether another window was clicked + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + bool click_on_window = false; + for (int i = gui.sub_windows.size() - 1; i >= 0; i--) { + SubWindow &sw = gui.sub_windows.write[i]; + + //clicked inside window? + + Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size()); + + if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) { + //check top bar + int title_height = sw.window->get_theme_constant("title_height"); + Rect2i title_bar = r; + title_bar.position.y -= title_height; + title_bar.size.y = title_height; + + if (title_bar.has_point(mb->get_position())) { + + click_on_window = true; + + int close_h_ofs = sw.window->get_theme_constant("close_h_ofs"); + int close_v_ofs = sw.window->get_theme_constant("close_v_ofs"); + Ref<Texture2D> close_icon = sw.window->get_theme_icon("close"); + + Rect2 close_rect; + close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs); + close_rect.size = close_icon->get_size(); + + if (gui.subwindow_focused != sw.window) { + //refocus + _sub_window_grab_focus(sw.window); + } + + if (close_rect.has_point(mb->get_position())) { + + gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE; + gui.subwindow_drag_close_inside = true; //starts inside + gui.subwindow_drag_close_rect = close_rect; + } else { + + gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE; + } + + gui.subwindow_drag_from = mb->get_position(); + gui.subwindow_drag_pos = sw.window->get_position(); + + _sub_window_update(sw.window); + } else { + gui.subwindow_resize_mode = _sub_window_get_resize_margin(sw.window, mb->get_position()); + if (gui.subwindow_resize_mode != SUB_WINDOW_RESIZE_DISABLED) { + gui.subwindow_resize_from_rect = r; + gui.subwindow_drag_from = mb->get_position(); + gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE; + click_on_window = true; + } + } + } + if (!click_on_window && r.has_point(mb->get_position())) { + //clicked, see if it needs to fetch focus + if (gui.subwindow_focused != sw.window) { + //refocus + _sub_window_grab_focus(sw.window); + } + + click_on_window = true; + } + + if (click_on_window) { + break; + } + } + + if (!click_on_window && gui.subwindow_focused) { + //no window found and clicked, remove focus + _sub_window_grab_focus(nullptr); + } + } + + if (gui.subwindow_focused) { + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + + SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position()); + if (resize != SUB_WINDOW_RESIZE_DISABLED) { + + DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = { + DisplayServer::CURSOR_ARROW, + DisplayServer::CURSOR_FDIAGSIZE, + DisplayServer::CURSOR_VSIZE, + DisplayServer::CURSOR_BDIAGSIZE, + DisplayServer::CURSOR_HSIZE, + DisplayServer::CURSOR_HSIZE, + DisplayServer::CURSOR_BDIAGSIZE, + DisplayServer::CURSOR_VSIZE, + DisplayServer::CURSOR_FDIAGSIZE + }; + + DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]); + + return true; //reserved for showing the resize cursor + } + } + } + + if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) { + return true; // dragging, don't pass the event + } + + if (!gui.subwindow_focused) { + return false; + } + + Transform2D window_ofs; + window_ofs.set_origin(-gui.subwindow_focused->get_position()); + + Ref<InputEvent> ev = p_event->xformed_by(window_ofs); + + gui.subwindow_focused->_window_input(ev); + + return true; +} + +void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { ERR_FAIL_COND(!is_inside_tree()); + if (disable_input) + return; + + if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { + return; + } + local_input_handled = false; + Ref<InputEvent> ev; + if (!p_local_coords) { + ev = _make_input_local(p_event); + } else { + ev = p_event; + } + + if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) { + set_input_as_handled(); + return; + } + if (!is_input_handled()) { - get_tree()->_call_input_pause(input_group, "_input", p_event); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input + get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input } if (!is_input_handled()) { - _gui_input_event(p_event); + _gui_input_event(ev); } - //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check + //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check } -void Viewport::unhandled_input(const Ref<InputEvent> &p_event) { +void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) { ERR_FAIL_COND(!is_inside_tree()); - get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", p_event); + if (disable_input) + return; + + if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { + return; + } + + Ref<InputEvent> ev; + if (!p_local_coords) { + ev = _make_input_local(p_event); + } else { + ev = p_event; + } + + get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this); //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev); - if (!get_tree()->input_handled && Object::cast_to<InputEventKey>(*p_event) != NULL) { - get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", p_event); + if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != NULL) { + get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this); //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev); } - if (physics_object_picking && !get_tree()->input_handled) { + if (physics_object_picking && !is_input_handled()) { - if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED && - (Object::cast_to<InputEventMouseButton>(*p_event) || - Object::cast_to<InputEventMouseMotion>(*p_event) || - Object::cast_to<InputEventScreenDrag>(*p_event) || - Object::cast_to<InputEventScreenTouch>(*p_event) || - Object::cast_to<InputEventKey>(*p_event) //to remember state + if (InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED && + (Object::cast_to<InputEventMouseButton>(*ev) || + Object::cast_to<InputEventMouseMotion>(*ev) || + Object::cast_to<InputEventScreenDrag>(*ev) || + Object::cast_to<InputEventScreenTouch>(*ev) || + Object::cast_to<InputEventKey>(*ev) //to remember state )) { - physics_picking_events.push_back(p_event); + physics_picking_events.push_back(ev); } } } @@ -2877,30 +3130,6 @@ bool Viewport::is_using_own_world() const { return own_world.is_valid(); } -void Viewport::set_attach_to_screen_rect(const Rect2 &p_rect) { - - VS::get_singleton()->viewport_attach_to_screen(viewport, p_rect); - to_screen_rect = p_rect; -} - -Rect2 Viewport::get_attach_to_screen_rect() const { - - return to_screen_rect; -} - -void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) { - - if (p_render_direct_to_screen == render_direct_to_screen) - return; - - render_direct_to_screen = p_render_direct_to_screen; - VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen); -} - -bool Viewport::is_using_render_direct_to_screen() const { - return render_direct_to_screen; -} - void Viewport::set_physics_object_picking(bool p_enable) { physics_object_picking = p_enable; @@ -2925,11 +3154,6 @@ Vector2 Viewport::get_camera_rect_size() const { return size; } -bool Viewport::gui_has_modal_stack() const { - - return gui.modal_stack.size(); -} - void Viewport::set_disable_input(bool p_disable) { disable_input = p_disable; } @@ -2943,10 +3167,6 @@ Variant Viewport::gui_get_drag_data() const { return gui.drag_data; } -Control *Viewport::get_modal_stack_top() const { - return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL; -} - String Viewport::get_configuration_warning() const { /*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) { @@ -3017,7 +3237,17 @@ void Viewport::set_input_as_handled() { local_input_handled = true; } else { ERR_FAIL_COND(!is_inside_tree()); - get_tree()->set_input_as_handled(); + Viewport *vp = this; + while (true) { + if (Object::cast_to<Window>(vp)) { + break; + } + if (!vp->get_parent()) { + break; + } + vp = vp->get_parent()->get_viewport(); + } + vp->set_input_as_handled(); } } @@ -3025,8 +3255,17 @@ bool Viewport::is_input_handled() const { if (handle_input_locally) { return local_input_handled; } else { - ERR_FAIL_COND_V(!is_inside_tree(), false); - return get_tree()->is_input_handled(); + const Viewport *vp = this; + while (true) { + if (Object::cast_to<Window>(vp)) { + break; + } + if (!vp->get_parent()) { + break; + } + vp = vp->get_parent()->get_viewport(); + } + return vp->is_input_handled(); } } @@ -3086,13 +3325,47 @@ void Viewport::_propagate_update_default_repeat(Node *p_node) { } } -void Viewport::_bind_methods() { +DisplayServer::WindowID Viewport::get_window_id() const { + return DisplayServer::MAIN_WINDOW_ID; +} - ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr); - ClassDB::bind_method(D_METHOD("use_arvr"), &Viewport::use_arvr); +Viewport *Viewport::get_parent_viewport() const { + ERR_FAIL_COND_V(!is_inside_tree(), nullptr); + if (!get_parent()) { + return nullptr; //root viewport + } + + return get_parent()->get_viewport(); +} + +void Viewport::set_embed_subwindows_hint(bool p_embed) { + gui.embed_subwindows_hint = p_embed; +} +bool Viewport::get_embed_subwindows_hint() const { + return gui.embed_subwindows_hint; +} +bool Viewport::is_embedding_subwindows() const { + return gui.embed_subwindows_hint; +} + +void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) { + ERR_FAIL_NULL(p_viewport); + ERR_FAIL_NULL(p_control); + + if (gui.mouse_focus) { + p_viewport->gui.mouse_focus = p_control; + p_viewport->gui.mouse_focus_mask = gui.mouse_focus_mask; + p_viewport->gui.key_focus = p_control; + p_viewport->gui.forced_mouse_focus = true; + + gui.mouse_focus = nullptr; + gui.forced_mouse_focus = false; + gui.mouse_focus_mask = 0; + } +} + +void Viewport::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_size", "size"), &Viewport::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &Viewport::get_size); ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d); ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d); ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d); @@ -3111,22 +3384,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background); ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background); - ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input); - ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text); - ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input); - - ClassDB::bind_method(D_METHOD("set_size_override", "enable", "size", "margin"), &Viewport::set_size_override, DEFVAL(Size2(-1, -1)), DEFVAL(Size2(0, 0))); - ClassDB::bind_method(D_METHOD("get_size_override"), &Viewport::get_size_override); - ClassDB::bind_method(D_METHOD("is_size_override_enabled"), &Viewport::is_size_override_enabled); - ClassDB::bind_method(D_METHOD("set_size_override_stretch", "enabled"), &Viewport::set_size_override_stretch); - ClassDB::bind_method(D_METHOD("is_size_override_stretch_enabled"), &Viewport::is_size_override_stretch_enabled); - - ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &Viewport::set_clear_mode); - ClassDB::bind_method(D_METHOD("get_clear_mode"), &Viewport::get_clear_mode); - - ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &Viewport::set_update_mode); - ClassDB::bind_method(D_METHOD("get_update_mode"), &Viewport::get_update_mode); - ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa); ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa); @@ -3141,8 +3398,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking); ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid); - ClassDB::bind_method(D_METHOD("input", "local_event"), &Viewport::input); - ClassDB::bind_method(D_METHOD("unhandled_input", "local_event"), &Viewport::unhandled_input); + ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text); + ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false)); ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds); @@ -3156,19 +3414,13 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); - ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect); - ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen); - ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen); ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); - ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack); ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data); ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); - ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top); - ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); @@ -3194,13 +3446,13 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_filter", "mode"), &Viewport::set_default_canvas_item_texture_filter); ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_filter"), &Viewport::get_default_canvas_item_texture_filter); + ClassDB::bind_method(D_METHOD("set_embed_subwindows_hint", "enable"), &Viewport::set_embed_subwindows_hint); + ClassDB::bind_method(D_METHOD("get_embed_subwindows_hint"), &Viewport::get_embed_subwindows_hint); + ClassDB::bind_method(D_METHOD("is_embedding_subwindows"), &Viewport::is_embedding_subwindows); + ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat); ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr"); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_override_stretch"), "set_size_override_stretch", "is_size_override_stretch_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d"); @@ -3208,11 +3460,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); - ADD_GROUP("Render Target", "render_target_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode"); ADD_GROUP("Canvas Items", "canvas_item_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat"); @@ -3224,6 +3472,7 @@ void Viewport::_bind_methods() { ADD_GROUP("GUI", "gui_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_embed_subwindows"), "set_embed_subwindows_hint", "get_embed_subwindows_hint"); ADD_GROUP("Shadow Atlas", "shadow_atlas_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size"); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0); @@ -3236,11 +3485,6 @@ void Viewport::_bind_methods() { ADD_SIGNAL(MethodInfo("size_changed")); ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); - BIND_ENUM_CONSTANT(UPDATE_DISABLED); - BIND_ENUM_CONSTANT(UPDATE_ONCE); - BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE); - BIND_ENUM_CONSTANT(UPDATE_ALWAYS); - BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1); BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4); @@ -3277,10 +3521,6 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(MSAA_8X); BIND_ENUM_CONSTANT(MSAA_16X); - BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); - BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER); - BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME); - BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST); BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR); BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS); @@ -3293,13 +3533,6 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX); } -void Viewport::_subwindow_visibility_changed() { - - // unfortunately, we don't know the sender, i.e. which subwindow changed; - // so we have to check them all. - gui.subwindow_visibility_dirty = true; -} - Viewport::Viewport() { world_2d = Ref<World2D>(memnew(World2D)); @@ -3307,8 +3540,6 @@ Viewport::Viewport() { viewport = VisualServer::get_singleton()->viewport_create(); texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport); - render_direct_to_screen = false; - default_texture.instance(); default_texture->vp = const_cast<Viewport *>(this); viewport_textures.insert(default_texture.ptr()); @@ -3324,14 +3555,10 @@ Viewport::Viewport() { camera = NULL; override_canvas_transform = false; canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport) - arvr = false; - size_override = false; - size_override_stretch = false; - size_override_size = Size2(1, 1); + gen_mipmaps = false; //clear=true; - update_mode = UPDATE_WHEN_VISIBLE; physics_object_picking = false; physics_has_last_mousepos = false; @@ -3368,12 +3595,14 @@ Viewport::Viewport() { gui.canvas_sort_index = 0; gui.roots_order_dirty = false; gui.mouse_focus = NULL; + gui.forced_mouse_focus = false; gui.last_mouse_focus = NULL; + gui.subwindow_focused = nullptr; + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; msaa = MSAA_DISABLED; debug_draw = DEBUG_DRAW_DISABLED; - clear_mode = CLEAR_MODE_ALWAYS; snap_controls_to_pixels = true; physics_last_mouse_state.alt = false; @@ -3384,6 +3613,8 @@ Viewport::Viewport() { local_input_handled = false; handle_input_locally = true; + size_allocated = false; + default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR; default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; } @@ -3398,3 +3629,95 @@ Viewport::~Viewport() { //SpatialSoundServer::get_singleton()->free(internal_listener); //SpatialSound2DServer::get_singleton()->free(internal_listener_2d); } + +///////////////////////////////// + +void SubViewport::set_use_arvr(bool p_use_arvr) { + arvr = p_use_arvr; + + VS::get_singleton()->viewport_set_use_arvr(get_viewport_rid(), arvr); +} + +bool SubViewport::is_using_arvr() { + return arvr; +} + +void SubViewport::set_size(const Size2i &p_size) { + _set_size(p_size, Size2i(), Rect2i(), Transform2D(), true); +} +Size2i SubViewport::get_size() const { + return _get_size(); +} + +void SubViewport::set_update_mode(UpdateMode p_mode) { + + update_mode = p_mode; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::ViewportUpdateMode(p_mode)); +} +SubViewport::UpdateMode SubViewport::get_update_mode() const { + + return update_mode; +} + +void SubViewport::set_clear_mode(ClearMode p_mode) { + + clear_mode = p_mode; + VS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), VS::ViewportClearMode(p_mode)); +} + +SubViewport::ClearMode SubViewport::get_clear_mode() const { + + return clear_mode; +} + +DisplayServer::WindowID SubViewport::get_window_id() const { + return DisplayServer::INVALID_WINDOW_ID; +} + +void SubViewport::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + VS::get_singleton()->viewport_set_active(get_viewport_rid(), true); + } + if (p_what == NOTIFICATION_EXIT_TREE) { + VS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + } +} + +void SubViewport::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &SubViewport::set_use_arvr); + ClassDB::bind_method(D_METHOD("is_using_arvr"), &SubViewport::is_using_arvr); + + ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size); + + ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &SubViewport::set_update_mode); + ClassDB::bind_method(D_METHOD("get_update_mode"), &SubViewport::get_update_mode); + + ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &SubViewport::set_clear_mode); + ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "is_using_arvr"); + ADD_GROUP("Render Target", "render_target_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode"); + + BIND_ENUM_CONSTANT(UPDATE_DISABLED); + BIND_ENUM_CONSTANT(UPDATE_ONCE); + BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE); + BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE); + BIND_ENUM_CONSTANT(UPDATE_ALWAYS); + + BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); + BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER); + BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME); +} + +SubViewport::SubViewport() { + arvr = false; + update_mode = UPDATE_WHEN_VISIBLE; + clear_mode = CLEAR_MODE_ALWAYS; +} + +SubViewport::~SubViewport() { +} diff --git a/scene/main/viewport.h b/scene/main/viewport.h index e511ce1b17..6b68bc0c94 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -35,6 +35,7 @@ #include "scene/main/node.h" #include "scene/resources/texture.h" #include "scene/resources/world_2d.h" +#include "servers/display_server.h" #include "servers/visual_server.h" class Camera; @@ -88,13 +89,6 @@ class Viewport : public Node { GDCLASS(Viewport, Node); public: - enum UpdateMode { - UPDATE_DISABLED, - UPDATE_ONCE, //then goes to disabled - UPDATE_WHEN_VISIBLE, // default - UPDATE_ALWAYS - }; - enum ShadowAtlasQuadrantSubdiv { SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED, SHADOW_ATLAS_QUADRANT_SUBDIV_1, @@ -142,13 +136,6 @@ public: DEBUG_DRAW_ROUGHNESS_LIMITER }; - enum ClearMode { - - CLEAR_MODE_ALWAYS, - CLEAR_MODE_NEVER, - CLEAR_MODE_ONLY_NEXT_FRAME - }; - enum DefaultCanvasItemTextureFilter { DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR, @@ -164,6 +151,10 @@ public: DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX, }; + enum { + SUBWINDOW_CANVAS_LAYER = 1024 + }; + private: friend class ViewportTexture; @@ -172,8 +163,6 @@ private: Listener *listener; Set<Listener *> listeners; - bool arvr; - struct CameraOverrideData { Transform transform; enum Projection { @@ -198,6 +187,7 @@ private: RID viewport; RID current_canvas; + RID subwindow_canvas; bool audio_listener; RID internal_listener; @@ -212,23 +202,17 @@ private: Transform2D global_canvas_transform; Transform2D stretch_transform; - Size2 size; - Rect2 to_screen_rect; - bool render_direct_to_screen; + Size2i size; + Size2i size_override; + bool size_allocated; RID contact_2d_debug; RID contact_3d_debug_multimesh; RID contact_3d_debug_instance; - bool size_override; - bool size_override_stretch; - Size2 size_override_size; - Size2 size_override_margin; - Rect2 last_vp_rect; bool transparent_bg; - ClearMode clear_mode; bool filter; bool gen_mipmaps; @@ -264,6 +248,7 @@ private: Ref<World> world; Ref<World> own_world; + Rect2i to_screen_rect; StringName input_group; StringName gui_input_group; StringName unhandled_input_group; @@ -276,10 +261,8 @@ private: void _propagate_exit_world(Node *p_node); void _propagate_viewport_notification(Node *p_node, int p_what); - void _update_stretch_transform(); void _update_global_transform(); - UpdateMode update_mode; RID texture_rid; DebugDraw debug_draw; @@ -291,9 +274,35 @@ private: Ref<ViewportTexture> default_texture; Set<ViewportTexture *> viewport_textures; + enum SubWindowDrag { + SUB_WINDOW_DRAG_DISABLED, + SUB_WINDOW_DRAG_MOVE, + SUB_WINDOW_DRAG_CLOSE, + SUB_WINDOW_DRAG_RESIZE, + }; + + enum SubWindowResize { + SUB_WINDOW_RESIZE_DISABLED, + SUB_WINDOW_RESIZE_TOP_LEFT, + SUB_WINDOW_RESIZE_TOP, + SUB_WINDOW_RESIZE_TOP_RIGHT, + SUB_WINDOW_RESIZE_LEFT, + SUB_WINDOW_RESIZE_RIGHT, + SUB_WINDOW_RESIZE_BOTTOM_LEFT, + SUB_WINDOW_RESIZE_BOTTOM, + SUB_WINDOW_RESIZE_BOTTOM_RIGHT, + SUB_WINDOW_RESIZE_MAX + }; + + struct SubWindow { + Window *window; + RID canvas_item; + }; + struct GUI { // info used when this is a window + bool forced_mouse_focus; //used for menu buttons bool key_event_accepted; Control *mouse_focus; Control *last_mouse_focus; @@ -301,8 +310,10 @@ private: int mouse_focus_mask; Control *key_focus; Control *mouse_over; + Control *drag_mouse_over; + Vector2 drag_mouse_over_pos; Control *tooltip; - Control *tooltip_popup; + Window *tooltip_popup; Label *tooltip_label; Point2 tooltip_pos; Point2 last_mouse_pos; @@ -312,16 +323,24 @@ private: Control *drag_preview; float tooltip_timer; float tooltip_delay; - List<Control *> modal_stack; Transform2D focus_inv_xform; - bool subwindow_order_dirty; - bool subwindow_visibility_dirty; - List<Control *> subwindows; // visible subwindows - List<Control *> all_known_subwindows; bool roots_order_dirty; List<Control *> roots; int canvas_sort_index; //for sorting items with canvas as root bool dragging; + bool embed_subwindows_hint; + bool embedding_subwindows; + + Window *subwindow_focused; + SubWindowDrag subwindow_drag; + Vector2 subwindow_drag_from; + Vector2 subwindow_drag_pos; + Rect2i subwindow_drag_close_rect; + bool subwindow_drag_close_inside; + SubWindowResize subwindow_resize_mode; + Rect2i subwindow_resize_from_rect; + + Vector<SubWindow> sub_windows; GUI(); } gui; @@ -337,10 +356,7 @@ private: void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); void _gui_call_notification(Control *p_control, int p_what); - void _gui_prepare_subwindows(); - void _gui_sort_subwindows(); void _gui_sort_roots(); - void _gui_sort_modal_stack(); Control *_gui_find_control(const Point2 &p_global); Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform); @@ -350,23 +366,13 @@ private: _FORCE_INLINE_ Transform2D _get_input_pre_xform() const; - void _vp_input(const Ref<InputEvent> &p_ev); - void _vp_input_text(const String &p_text); - void _vp_unhandled_input(const Ref<InputEvent> &p_ev); Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev); friend class Control; List<Control *>::Element *_gui_add_root_control(Control *p_control); - List<Control *>::Element *_gui_add_subwindow_control(Control *p_control); - - void _gui_set_subwindow_order_dirty(); - void _gui_set_root_order_dirty(); - void _gui_remove_modal_control(List<Control *>::Element *MI); - void _gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner); void _gui_remove_root_control(List<Control *>::Element *RI); - void _gui_remove_subwindow_control(List<Control *>::Element *SI); String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL); void _gui_cancel_tooltip(); @@ -378,9 +384,6 @@ private: void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control); void _gui_set_drag_preview(Control *p_base, Control *p_control); - bool _gui_is_modal_on_top(const Control *p_control); - List<Control *>::Element *_gui_show_modal(Control *p_control); - void _gui_remove_focus(); void _gui_unfocus_control(Control *p_control); bool _gui_control_has_focus(const Control *p_control); @@ -391,8 +394,6 @@ private: Control *_gui_get_focus_owner(); - Vector2 _get_window_offset() const; - bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check); friend class Listener; @@ -418,9 +419,26 @@ private: void _update_canvas_items(Node *p_node); + void _gui_set_root_order_dirty(); + void _own_world_changed(); + friend class Window; + + void _sub_window_update_order(); + void _sub_window_register(Window *p_window); + void _sub_window_update(Window *p_window); + void _sub_window_grab_focus(Window *p_window); + void _sub_window_remove(Window *p_window); + bool _sub_windows_forward_input(const Ref<InputEvent> &p_event); + SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point); + protected: + void _set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated); + + Size2i _get_size() const; + bool _is_size_allocated() const; + void _notification(int p_what); static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const; @@ -438,19 +456,14 @@ public: void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far); - void set_use_arvr(bool p_use_arvr); - bool use_arvr(); - void set_as_audio_listener(bool p_enable); bool is_audio_listener() const; void set_as_audio_listener_2d(bool p_enable); bool is_audio_listener_2d() const; - void set_size(const Size2 &p_size); void update_canvas_items(); - Size2 get_size() const; Rect2 get_visible_rect() const; RID get_viewport_rid() const; @@ -479,18 +492,6 @@ public: void set_transparent_background(bool p_enable); bool has_transparent_background() const; - void set_size_override(bool p_enable, const Size2 &p_size = Size2(-1, -1), const Vector2 &p_margin = Vector2()); - Size2 get_size_override() const; - - bool is_size_override_enabled() const; - void set_size_override_stretch(bool p_enable); - bool is_size_override_stretch_enabled() const; - - void set_clear_mode(ClearMode p_mode); - ClearMode get_clear_mode() const; - - void set_update_mode(UpdateMode p_mode); - UpdateMode get_update_mode() const; Ref<ViewportTexture> get_texture() const; void set_shadow_atlas_size(int p_size); @@ -508,28 +509,20 @@ public: void set_use_own_world(bool p_world); bool is_using_own_world() const; - void input(const Ref<InputEvent> &p_event); - void unhandled_input(const Ref<InputEvent> &p_event); + void input_text(const String &p_text); + void input(const Ref<InputEvent> &p_event, bool p_local_coords = false); + void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false); void set_disable_input(bool p_disable); bool is_input_disabled() const; - void set_attach_to_screen_rect(const Rect2 &p_rect); - Rect2 get_attach_to_screen_rect() const; - - void set_use_render_direct_to_screen(bool p_render_direct_to_screen); - bool is_using_render_direct_to_screen() const; - Vector2 get_mouse_position() const; void warp_mouse(const Vector2 &p_pos); void set_physics_object_picking(bool p_enable); bool get_physics_object_picking(); - bool gui_has_modal_stack() const; - Variant gui_get_drag_data() const; - Control *get_modal_stack_top() const; void gui_reset_canvas_sort_index(); int gui_get_canvas_sort_index(); @@ -544,8 +537,6 @@ public: void set_snap_controls_to_pixels(bool p_enable); bool is_snap_controls_to_pixels_enabled() const; - void _subwindow_visibility_changed(); - void set_input_as_handled(); bool is_input_handled() const; @@ -560,15 +551,71 @@ public: void set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat); DefaultCanvasItemTextureRepeat get_default_canvas_item_texture_repeat() const; + virtual DisplayServer::WindowID get_window_id() const = 0; + + void set_embed_subwindows_hint(bool p_embed); + bool get_embed_subwindows_hint() const; + bool is_embedding_subwindows() const; + + Viewport *get_parent_viewport() const; + + void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control); + Viewport(); ~Viewport(); }; -VARIANT_ENUM_CAST(Viewport::UpdateMode); +class SubViewport : public Viewport { + + GDCLASS(SubViewport, Viewport); + +public: + enum ClearMode { + + CLEAR_MODE_ALWAYS, + CLEAR_MODE_NEVER, + CLEAR_MODE_ONLY_NEXT_FRAME + }; + + enum UpdateMode { + UPDATE_DISABLED, + UPDATE_ONCE, //then goes to disabled + UPDATE_WHEN_VISIBLE, // default + UPDATE_WHEN_PARENT_VISIBLE, + UPDATE_ALWAYS + }; + +private: + UpdateMode update_mode; + ClearMode clear_mode; + bool arvr; + +protected: + static void _bind_methods(); + virtual DisplayServer::WindowID get_window_id() const; + void _notification(int p_what); + +public: + void set_size(const Size2i &p_size); + Size2i get_size() const; + + void set_use_arvr(bool p_use_arvr); + bool is_using_arvr(); + + void set_update_mode(UpdateMode p_mode); + UpdateMode get_update_mode() const; + + void set_clear_mode(ClearMode p_mode); + ClearMode get_clear_mode() const; + + SubViewport(); + ~SubViewport(); +}; +VARIANT_ENUM_CAST(SubViewport::UpdateMode); VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv); VARIANT_ENUM_CAST(Viewport::MSAA); VARIANT_ENUM_CAST(Viewport::DebugDraw); -VARIANT_ENUM_CAST(Viewport::ClearMode); +VARIANT_ENUM_CAST(SubViewport::ClearMode); VARIANT_ENUM_CAST(Viewport::RenderInfo); VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter); VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat); diff --git a/scene/main/window.cpp b/scene/main/window.cpp new file mode 100644 index 0000000000..a2a49aea75 --- /dev/null +++ b/scene/main/window.cpp @@ -0,0 +1,1406 @@ +/*************************************************************************/ +/* window.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "window.h" + +#include "core/debugger/engine_debugger.h" +#include "core/os/keyboard.h" +#include "scene/gui/control.h" +#include "scene/resources/dynamic_font.h" +#include "scene/scene_string_names.h" + +void Window::set_title(const String &p_title) { + title = p_title; + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_title(p_title, window_id); + } +} +String Window::get_title() const { + return title; +} + +void Window::set_current_screen(int p_screen) { + current_screen = p_screen; + if (window_id == DisplayServer::INVALID_WINDOW_ID) + return; + DisplayServer::get_singleton()->window_set_current_screen(p_screen, window_id); +} +int Window::get_current_screen() const { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id); + } + return current_screen; +} + +void Window::set_position(const Point2i &p_position) { + + position = p_position; + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_position(p_position, window_id); + } +} +Point2i Window::get_position() const { + return position; +} + +void Window::set_size(const Size2i &p_size) { + size = p_size; + _update_window_size(); +} +Size2i Window::get_size() const { + + return size; +} + +Size2i Window::get_real_size() const { + + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_get_real_size(window_id); + } + return size; +} + +void Window::set_max_size(const Size2i &p_max_size) { + max_size = p_max_size; + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); + } + _update_window_size(); +} + +Size2i Window::get_max_size() const { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + max_size = DisplayServer::get_singleton()->window_get_max_size(window_id); + } + return max_size; +} + +void Window::set_min_size(const Size2i &p_min_size) { + min_size = p_min_size; + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); + } + _update_window_size(); +} + +Size2i Window::get_min_size() const { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + min_size = DisplayServer::get_singleton()->window_get_min_size(window_id); + } + return min_size; +} + +void Window::set_mode(Mode p_mode) { + + mode = p_mode; + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id); + } +} + +Window::Mode Window::get_mode() const { + + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id); + } + return mode; +} + +void Window::set_flag(Flags p_flag, bool p_enabled) { + ERR_FAIL_INDEX(p_flag, FLAG_MAX); + flags[p_flag] = p_enabled; + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); + } +} + +bool Window::get_flag(Flags p_flag) const { + ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); + } + return flags[p_flag]; +} + +bool Window::is_maximize_allowed() const { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id); + } + return true; +} + +void Window::request_attention() { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_request_attention(window_id); + } +} +void Window::move_to_foreground() { + + if (embedder) { + embedder->_sub_window_grab_focus(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_move_to_foreground(window_id); + } +} + +bool Window::can_draw() const { + if (!is_inside_tree()) { + return false; + } + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_can_draw(window_id); + } + + return visible; +} + +void Window::set_ime_active(bool p_active) { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id); + } +} +void Window::set_ime_position(const Point2i &p_pos) { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id); + } +} + +bool Window::is_embedded() const { + ERR_FAIL_COND_V(!is_inside_tree(), false); + + return _get_embedder() != nullptr; +} + +void Window::_make_window() { + ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID); + + uint32_t f = 0; + for (int i = 0; i < FLAG_MAX; i++) { + if (flags[i]) { + f |= (1 << i); + } + } + + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size)); + ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); + DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); + DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); + DisplayServer::get_singleton()->window_set_title(title, window_id); + DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); + + _update_window_size(); + + if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); + } + + for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) { + if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id); + } + } + + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE); +} +void Window::_update_from_window() { + + ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id); + for (int i = 0; i < FLAG_MAX; i++) { + flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id); + } +} + +void Window::_clear_window() { + ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + + if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); + } + + for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) { + if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, DisplayServer::INVALID_WINDOW_ID); + } + } + + _update_from_window(); + + DisplayServer::get_singleton()->delete_sub_window(window_id); + window_id = DisplayServer::INVALID_WINDOW_ID; + + _update_viewport_size(); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); +} + +void Window::_rect_changed_callback(const Rect2i &p_callback) { + + //we must always accept this as the truth + if (size == p_callback.size && position == p_callback.position) { + return; + } + position = p_callback.position; + + if (size != p_callback.size) { + size = p_callback.size; + _update_viewport_size(); + } +} + +void Window::_propagate_window_notification(Node *p_node, int p_notification) { + p_node->notification(p_notification); + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + Window *window = Object::cast_to<Window>(child); + if (window) { + break; + } + _propagate_window_notification(child, p_notification); + } +} + +void Window::_event_callback(DisplayServer::WindowEvent p_event) { + + switch (p_event) { + case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { + _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); + emit_signal("mouse_entered"); + } break; + case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { + _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); + emit_signal("mouse_exited"); + } break; + case DisplayServer::WINDOW_EVENT_FOCUS_IN: { + focused = true; + _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_IN); + emit_signal("focus_entered"); + + } break; + case DisplayServer::WINDOW_EVENT_FOCUS_OUT: { + focused = false; + _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_OUT); + emit_signal("focus_exited"); + } break; + case DisplayServer::WINDOW_EVENT_CLOSE_REQUEST: { + if (exclusive_child != nullptr) { + break; //has an exclusive child, can't get events until child is closed + } + _propagate_window_notification(this, NOTIFICATION_WM_CLOSE_REQUEST); + emit_signal("close_requested"); + } break; + case DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST: { + _propagate_window_notification(this, NOTIFICATION_WM_GO_BACK_REQUEST); + emit_signal("go_back_requested"); + } break; + case DisplayServer::WINDOW_EVENT_DPI_CHANGE: { + _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE); + emit_signal("dpi_changed"); + } break; + } +} + +void Window::show() { + set_visible(true); +} +void Window::hide() { + set_visible(false); +} + +void Window::set_visible(bool p_visible) { + + if (visible == p_visible) { + return; + } + + visible = p_visible; + + if (!is_inside_tree()) { + return; + } + + if (updating_child_controls) { + _update_child_controls(); + } + + ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window."); + + Viewport *embedder_vp = _get_embedder(); + + if (!embedder_vp) { + if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) { + _clear_window(); + } + if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) { + _make_window(); + _update_window_callbacks(); + } + } else { + if (visible) { + embedder = embedder_vp; + embedder->_sub_window_register(this); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); + } else { + embedder->_sub_window_remove(this); + embedder = nullptr; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); + } + _update_window_size(); + } + + if (!visible) { + focused = false; + } + notification(NOTIFICATION_VISIBILITY_CHANGED); + emit_signal(SceneStringNames::get_singleton()->visibility_changed); + + VS::get_singleton()->viewport_set_active(get_viewport_rid(), visible); +} + +void Window::_clear_transient() { + if (transient_parent) { + if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); + } + transient_parent->transient_children.erase(this); + if (transient_parent->exclusive_child == this) { + transient_parent->exclusive_child = nullptr; + } + transient_parent = nullptr; + } +} + +void Window::_make_transient() { + if (!get_parent()) { + //main window, can't be transient + return; + } + //find transient parent + Viewport *vp = get_parent()->get_viewport(); + Window *window = nullptr; + while (vp) { + window = Object::cast_to<Window>(vp); + if (window) { + break; + } + if (!vp->get_parent()) { + break; + } + + vp = vp->get_parent()->get_viewport(); + } + + if (window) { + transient_parent = window; + window->transient_children.insert(this); + if (is_inside_tree() && is_visible() && exclusive) { + if (transient_parent->exclusive_child == nullptr) { + transient_parent->exclusive_child = this; + } else if (transient_parent->exclusive_child != this) { + ERR_PRINT("Making child transient exclusive, but parent has another exclusive child"); + } + } + } + + //see if we can make transient + if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); + } +} + +void Window::set_transient(bool p_transient) { + if (transient == p_transient) { + return; + } + + transient = p_transient; + + if (!is_inside_tree()) { + return; + } + + if (transient) { + _make_transient(); + } else { + _clear_transient(); + } +} +bool Window::is_transient() const { + return transient; +} + +void Window::set_exclusive(bool p_exclusive) { + + if (exclusive == p_exclusive) { + return; + } + + exclusive = p_exclusive; + + if (transient_parent) { + if (p_exclusive && is_inside_tree() && is_visible()) { + ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); + transient_parent->exclusive_child = this; + } else { + if (transient_parent->exclusive_child == this) { + transient_parent->exclusive_child = nullptr; + } + } + } +} + +bool Window::is_exclusive() const { + return exclusive; +} + +bool Window::is_visible() const { + return visible; +} + +void Window::_update_window_size() { + + Size2i size_limit; + if (wrap_controls) { + size_limit = get_contents_minimum_size(); + } + + size_limit.x = MAX(size_limit.x, min_size.x); + size_limit.y = MAX(size_limit.y, min_size.y); + + size.x = MAX(size_limit.x, size.x); + size.y = MAX(size_limit.y, size.y); + + if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) { + size.x = max_size.x; + } + + if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) { + size.y = max_size.y; + } + + if (embedder) { + embedder->_sub_window_update(this); + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_size(size, window_id); + } + + //update the viewport + _update_viewport_size(); +} +void Window::_update_viewport_size() { + //update the viewport part + + Size2i final_size; + Size2i final_size_override; + Rect2i attach_to_screen_rect(Point2i(), size); + Transform2D stretch_transform; + float font_oversampling = 1.0; + + if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) { + + stretch_transform = Transform2D(); + final_size = size; + + } else { + + //actual screen video mode + Size2 video_mode = size; + Size2 desired_res = content_scale_size; + + Size2 viewport_size; + Size2 screen_size; + + float viewport_aspect = desired_res.aspect(); + float video_mode_aspect = video_mode.aspect(); + + if (content_scale_aspect == CONTENT_SCALE_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { + //same aspect or ignore aspect + viewport_size = desired_res; + screen_size = video_mode; + } else if (viewport_aspect < video_mode_aspect) { + // screen ratio is smaller vertically + + if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_HEIGHT || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) { + + //will stretch horizontally + viewport_size.x = desired_res.y * video_mode_aspect; + viewport_size.y = desired_res.y; + screen_size = video_mode; + + } else { + //will need black bars + viewport_size = desired_res; + screen_size.x = video_mode.y * viewport_aspect; + screen_size.y = video_mode.y; + } + } else { + //screen ratio is smaller horizontally + if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_WIDTH || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) { + + //will stretch horizontally + viewport_size.x = desired_res.x; + viewport_size.y = desired_res.x / video_mode_aspect; + screen_size = video_mode; + + } else { + //will need black bars + viewport_size = desired_res; + screen_size.x = video_mode.x; + screen_size.y = video_mode.x / viewport_aspect; + } + } + + screen_size = screen_size.floor(); + viewport_size = viewport_size.floor(); + + Size2 margin; + Size2 offset; + //black bars and margin + if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.x < video_mode.x) { + margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); + //VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0); + offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); + } else if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.y < video_mode.y) { + margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); + //VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y); + offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); + } else { + //VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0); + } + + switch (content_scale_mode) { + case CONTENT_SCALE_MODE_DISABLED: { + // Already handled above + //_update_font_oversampling(1.0); + } break; + case CONTENT_SCALE_MODE_OBJECTS: { + + final_size = screen_size; + final_size_override = viewport_size; + attach_to_screen_rect = Rect2(margin, screen_size); + font_oversampling = screen_size.x / viewport_size.x; + } break; + case CONTENT_SCALE_MODE_PIXELS: { + + final_size = viewport_size; + attach_to_screen_rect = Rect2(margin, screen_size); + + } break; + } + + Size2 scale = size / (Vector2(final_size) + margin * 2); + stretch_transform.scale(scale); + stretch_transform.elements[2] = margin * scale; + } + + bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr); + + _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate); + + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + VisualServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id); + } else { + VisualServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), Rect2i(), DisplayServer::INVALID_WINDOW_ID); + } + + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + + if (!use_font_oversampling) { + font_oversampling = 1.0; + } + if (DynamicFontAtSize::font_oversampling != font_oversampling) { + + DynamicFontAtSize::font_oversampling = font_oversampling; + DynamicFont::update_oversampling(); + } + } + + notification(NOTIFICATION_WM_SIZE_CHANGED); + + if (embedder) { + embedder->_sub_window_update(this); + } +} + +void Window::_update_window_callbacks() { + DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id); + DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id); + DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id); + DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id); + DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id); +} + +Viewport *Window::_get_embedder() const { + + Viewport *vp = get_parent_viewport(); + + while (vp) { + + if (vp->is_embedding_subwindows()) { + return vp; + } + + if (vp->get_parent()) { + vp = vp->get_parent()->get_viewport(); + } else { + vp = nullptr; + } + } + return nullptr; +} + +void Window::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + + bool embedded = false; + { + + embedder = _get_embedder(); + + if (embedder) { + embedded = true; + + if (!visible) { + embedder = nullptr; //not yet since not visible + } + } + } + + if (embedded) { + //create as embedded + if (embedder) { + embedder->_sub_window_register(this); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); + _update_window_size(); + } + + } else { + if (get_parent() == nullptr) { + //it's the root window! + visible = true; //always visible + window_id = DisplayServer::MAIN_WINDOW_ID; + DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); + _update_from_window(); + //since this window already exists (created on start), we must update pos and size from it + { + position = DisplayServer::get_singleton()->window_get_position(window_id); + size = DisplayServer::get_singleton()->window_get_size(window_id); + } + _update_viewport_size(); //then feed back to the viewport + _update_window_callbacks(); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE); + } else { + //create + if (visible) { + _make_window(); + _update_window_callbacks(); + } + } + } + + if (transient) { + _make_transient(); + } + if (visible) { + notification(NOTIFICATION_VISIBILITY_CHANGED); + emit_signal(SceneStringNames::get_singleton()->visibility_changed); + VS::get_singleton()->viewport_set_active(get_viewport_rid(), true); + } + } + + if (p_what == NOTIFICATION_READY) { + + if (wrap_controls) { + _update_child_controls(); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + + if (transient) { + _clear_transient(); + } + + if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) { + + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); + _update_window_callbacks(); + } else { + _clear_window(); + } + } else { + + if (embedder) { + embedder->_sub_window_remove(this); + embedder = nullptr; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); + } + _update_viewport_size(); //called by clear and make, which does not happen here + } + + VS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + } +} + +void Window::set_content_scale_size(const Size2i &p_size) { + ERR_FAIL_COND(p_size.x < 0); + ERR_FAIL_COND(p_size.y < 0); + content_scale_size = p_size; + _update_viewport_size(); +} + +Size2i Window::get_content_scale_size() const { + return content_scale_size; +} + +void Window::set_content_scale_mode(ContentScaleMode p_mode) { + content_scale_mode = p_mode; + _update_viewport_size(); +} +Window::ContentScaleMode Window::get_content_scale_mode() const { + return content_scale_mode; +} + +void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) { + content_scale_aspect = p_aspect; + _update_viewport_size(); +} +Window::ContentScaleAspect Window::get_content_scale_aspect() const { + return content_scale_aspect; +} + +void Window::set_use_font_oversampling(bool p_oversampling) { + if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) { + ERR_FAIL_MSG("Only the root window can set and use font oversampling."); + } + use_font_oversampling = p_oversampling; + _update_viewport_size(); +} +bool Window::is_using_font_oversampling() const { + return use_font_oversampling; +} + +DisplayServer::WindowID Window::get_window_id() const { + return window_id; +} + +void Window::set_wrap_controls(bool p_enable) { + wrap_controls = p_enable; + if (wrap_controls) { + child_controls_changed(); + } +} + +bool Window::is_wrapping_controls() const { + return wrap_controls; +} + +Size2 Window::_get_contents_minimum_size() const { + Size2 max; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (c) { + Point2i pos = c->get_position(); + Size2i min = c->get_combined_minimum_size(); + + max.x = MAX(pos.x + min.x, max.x); + max.y = MAX(pos.y + min.y, max.y); + } + } + + return max; +} +void Window::_update_child_controls() { + + if (!updating_child_controls) { + return; + } + + _update_window_size(); + + updating_child_controls = false; +} +void Window::child_controls_changed() { + + if (!is_inside_tree() || !visible || updating_child_controls) { + return; + } + + updating_child_controls = true; + call_deferred("_update_child_controls"); +} + +void Window::_window_input(const Ref<InputEvent> &p_ev) { + if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_ev.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_ev))) + return; //avoid joy input on editor + + if (EngineDebugger::is_active()) { + //quit from game window using F8 + Ref<InputEventKey> k = p_ev; + if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) { + EngineDebugger::get_singleton()->send_message("request_quit", Array()); + } + } + + if (exclusive_child != nullptr) { + exclusive_child->grab_focus(); + + return; //has an exclusive child, can't get events until child is closed + } + + emit_signal(SceneStringNames::get_singleton()->window_input, p_ev); + input(p_ev); + if (!is_input_handled()) { + unhandled_input(p_ev); + } +} +void Window::_window_input_text(const String &p_text) { + input_text(p_text); +} +void Window::_window_drop_files(const Vector<String> &p_files) { + emit_signal("files_dropped", p_files); +} + +Viewport *Window::get_parent_viewport() const { + + if (get_parent()) { + return get_parent()->get_viewport(); + } else { + return nullptr; + } +} + +Window *Window::get_parent_visible_window() const { + + Viewport *vp = get_parent_viewport(); + Window *window = nullptr; + while (vp) { + window = Object::cast_to<Window>(vp); + if (window && window->visible) { + break; + } + if (!vp->get_parent()) { + break; + } + + vp = vp->get_parent()->get_viewport(); + } + return window; +} + +void Window::popup_on_parent(const Rect2i &p_parent_rect) { + + ERR_FAIL_COND(!is_inside_tree()); + ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); + + if (!is_embedded()) { + Window *window = get_parent_visible_window(); + + if (!window) { + popup(p_parent_rect); + } else { + popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size)); + } + } else { + popup(p_parent_rect); + } +} + +void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) { + + ERR_FAIL_COND(!is_inside_tree()); + ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); + + Rect2 parent_rect; + + if (is_embedded()) { + parent_rect = get_parent_viewport()->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); + parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); + parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); + } + + Vector2i size_ratio = parent_rect.size * p_fallback_ratio; + + Rect2i popup_rect; + popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y)); + popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + + popup(popup_rect); +} + +void Window::popup_centered(const Size2i &p_minsize) { + ERR_FAIL_COND(!is_inside_tree()); + ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); + + Rect2 parent_rect; + + if (is_embedded()) { + parent_rect = get_parent_viewport()->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); + parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); + parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); + } + + Rect2i popup_rect; + if (p_minsize == Size2i()) { + popup_rect.size = _get_contents_minimum_size(); + } else { + popup_rect.size = p_minsize; + } + popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + + popup(popup_rect); +} + +void Window::popup_centered_ratio(float p_ratio) { + + ERR_FAIL_COND(!is_inside_tree()); + ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); + + Rect2i parent_rect; + + if (is_embedded()) { + parent_rect = get_parent_viewport()->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); + parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); + parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); + } + + Rect2i popup_rect; + popup_rect.size = parent_rect.size * p_ratio; + popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + + popup(popup_rect); +} + +void Window::popup(const Rect2i &p_screen_rect) { + + emit_signal("about_to_popup"); + + if (p_screen_rect != Rect2i()) { + set_position(p_screen_rect.position); + set_size(p_screen_rect.size); + } + + Rect2i adjust = _popup_adjust_rect(); + if (adjust != Rect2i()) { + set_position(adjust.position); + set_size(adjust.size); + } + + set_transient(true); + set_visible(true); + _post_popup(); + notification(NOTIFICATION_POST_POPUP); +} + +Size2 Window::get_contents_minimum_size() const { + return _get_contents_minimum_size(); +} + +void Window::grab_focus() { + if (embedder) { + embedder->_sub_window_grab_focus(this); + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_move_to_foreground(window_id); + } +} + +bool Window::has_focus() const { + return focused; +} + +Rect2i Window::get_usable_parent_rect() const { + ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); + Rect2i parent; + if (is_embedded()) { + parent = _get_embedder()->get_visible_rect(); + } else { + + const Window *w = is_visible() ? this : get_parent_visible_window(); + //find a parent that can contain us + ERR_FAIL_COND_V(!w, Rect2()); + + parent = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id())); + } + return parent; +} + +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, NULL, NULL); + } + + Window *child_w = Object::cast_to<Window>(p_child); + + if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { + Control::_propagate_theme_changed(child_w, NULL, NULL); + } + + if (is_inside_tree() && wrap_controls) { + child_controls_changed(); + } +} + +void Window::set_theme(const Ref<Theme> &p_theme) { + + if (theme == p_theme) + return; + + theme = p_theme; + + 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); + } + } + } +} +Ref<Theme> Window::get_theme() const { + return theme; +} + +Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_icons(theme_owner, theme_owner_window, p_name, type); +} +Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_shaders(theme_owner, theme_owner_window, p_name, type); +} +Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type); +} +Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_fonts(theme_owner, theme_owner_window, p_name, type); +} +Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_colors(theme_owner, theme_owner_window, p_name, type); +} +int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::get_constants(theme_owner, theme_owner_window, p_name, type); +} + +bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_icons(theme_owner, theme_owner_window, p_name, type); +} +bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_shaders(theme_owner, theme_owner_window, p_name, type); +} +bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type); +} +bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_fonts(theme_owner, theme_owner_window, p_name, type); +} +bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_colors(theme_owner, theme_owner_window, p_name, type); +} +bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const { + StringName type = p_type ? p_type : get_class_name(); + return Control::has_constants(theme_owner, theme_owner_window, p_name, type); +} + +Rect2i Window::get_parent_rect() const { + ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); + if (is_embedded()) { + //viewport + Node *n = get_parent(); + ERR_FAIL_COND_V(!n, Rect2i()); + Viewport *p = n->get_viewport(); + ERR_FAIL_COND_V(!p, Rect2i()); + + return p->get_visible_rect(); + } else { + int x = get_position().x; + int closest_dist = 0x7FFFFFFF; + Rect2i closest_rect; + for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { + Rect2i s(DisplayServer::get_singleton()->screen_get_position(i), DisplayServer::get_singleton()->screen_get_size(i)); + int d; + if (x >= s.position.x && x < s.size.x) { + //contained + closest_rect = s; + break; + } else if (x < s.position.x) { + d = s.position.x - x; + } else { + d = x - (s.position.x + s.size.x); + } + + if (d < closest_dist) { + closest_dist = d; + closest_rect = s; + } + } + return closest_rect; + } +} + +void Window::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title); + ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title); + + ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen); + ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen); + + ClassDB::bind_method(D_METHOD("set_position", "position"), &Window::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &Window::get_position); + + ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size); + + ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size); + + ClassDB::bind_method(D_METHOD("set_max_size", "max_size"), &Window::set_max_size); + ClassDB::bind_method(D_METHOD("get_max_size"), &Window::get_max_size); + + ClassDB::bind_method(D_METHOD("set_min_size", "min_size"), &Window::set_min_size); + ClassDB::bind_method(D_METHOD("get_min_size"), &Window::get_min_size); + + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Window::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &Window::get_mode); + + ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &Window::set_flag); + ClassDB::bind_method(D_METHOD("get_flag", "flag"), &Window::get_flag); + + ClassDB::bind_method(D_METHOD("is_maximize_allowed"), &Window::is_maximize_allowed); + + ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention); + + ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground); + + ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible); + ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible); + + ClassDB::bind_method(D_METHOD("hide"), &Window::hide); + ClassDB::bind_method(D_METHOD("show"), &Window::show); + + ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient); + ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient); + + ClassDB::bind_method(D_METHOD("set_exclusive", "exclusive"), &Window::set_exclusive); + ClassDB::bind_method(D_METHOD("is_exclusive"), &Window::is_exclusive); + + ClassDB::bind_method(D_METHOD("can_draw"), &Window::is_transient); + ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus); + ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus); + + ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active); + ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position); + + ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded); + + ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size); + ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size); + + ClassDB::bind_method(D_METHOD("set_content_scale_mode", "mode"), &Window::set_content_scale_mode); + ClassDB::bind_method(D_METHOD("get_content_scale_mode"), &Window::get_content_scale_mode); + + ClassDB::bind_method(D_METHOD("set_content_scale_aspect", "aspect"), &Window::set_content_scale_aspect); + ClassDB::bind_method(D_METHOD("get_content_scale_aspect"), &Window::get_content_scale_aspect); + + ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling); + ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling); + + ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls); + ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls); + ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed); + + ClassDB::bind_method(D_METHOD("_update_child_controls"), &Window::_update_child_controls); + + ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme); + ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme); + + ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "type"), &Window::get_theme_icon, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Window::get_theme_stylebox, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Window::get_theme_font, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Window::get_theme_color, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Window::get_theme_constant, DEFVAL("")); + + ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Window::has_theme_icon, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Window::has_theme_stylebox, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Window::has_theme_font, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Window::has_theme_color, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Window::has_theme_constant, DEFVAL("")); + + ClassDB::bind_method(D_METHOD("popup", "rect"), &Window::popup, DEFVAL(Rect2i())); + ClassDB::bind_method(D_METHOD("popup_on_parent", "parent_rect"), &Window::popup_on_parent); + ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Window::popup_centered_ratio, DEFVAL(0.8)); + ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i())); + ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered, DEFVAL(Size2i()), DEFVAL(0.75)); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,FullScreen"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_screen"), "set_current_screen", "get_current_screen"); + ADD_GROUP("Flags", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive"), "set_exclusive", "is_exclusive"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP); + 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_GROUP("Limits", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size"); + ADD_GROUP("Content Scale", "content_scale_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Object,Pixels"), "set_content_scale_mode", "get_content_scale_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,KeepWidth,KeepHeight,Expand"), "set_content_scale_aspect", "get_content_scale_aspect"); + ADD_GROUP("Theme", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme"); + + ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); + ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); + ADD_SIGNAL(MethodInfo("mouse_entered")); + ADD_SIGNAL(MethodInfo("mouse_exited")); + ADD_SIGNAL(MethodInfo("focus_entered")); + ADD_SIGNAL(MethodInfo("focus_exited")); + ADD_SIGNAL(MethodInfo("close_requested")); + ADD_SIGNAL(MethodInfo("go_back_requested")); + ADD_SIGNAL(MethodInfo("visibility_changed")); + ADD_SIGNAL(MethodInfo("about_to_popup")); + + BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); + + BIND_ENUM_CONSTANT(MODE_WINDOWED); + BIND_ENUM_CONSTANT(MODE_MINIMIZED); + BIND_ENUM_CONSTANT(MODE_MAXIMIZED); + BIND_ENUM_CONSTANT(MODE_FULLSCREEN); + + BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED); + BIND_ENUM_CONSTANT(FLAG_BORDERLESS); + BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP); + BIND_ENUM_CONSTANT(FLAG_TRANSPARENT); + BIND_ENUM_CONSTANT(FLAG_NO_FOCUS); + BIND_ENUM_CONSTANT(FLAG_MAX); + + BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); + BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_OBJECTS); + BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_PIXELS); + + BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_IGNORE); + BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP); + BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_WIDTH); + BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT); + BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND); +} + +Window::Window() { + for (int i = 0; i < FLAG_MAX; i++) { + flags[i] = false; + } + content_scale_mode = CONTENT_SCALE_MODE_DISABLED; + content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); +} +Window::~Window() { +} diff --git a/scene/main/window.h b/scene/main/window.h new file mode 100644 index 0000000000..be07762f20 --- /dev/null +++ b/scene/main/window.h @@ -0,0 +1,266 @@ +/*************************************************************************/ +/* window.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include "scene/main/viewport.h" +#include "scene/resources/theme.h" +#include "servers/display_server.h" + +class Control; +class Window : public Viewport { + GDCLASS(Window, Viewport) +public: + enum Mode { + MODE_WINDOWED = DisplayServer::WINDOW_MODE_WINDOWED, + MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED, + MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED, + MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN + }; + + enum Flags { + FLAG_RESIZE_DISABLED = DisplayServer::WINDOW_FLAG_RESIZE_DISABLED, + FLAG_BORDERLESS = DisplayServer::WINDOW_FLAG_BORDERLESS, + FLAG_ALWAYS_ON_TOP = DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, + FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT, + FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS, + FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX, + }; + + enum ContentScaleMode { + CONTENT_SCALE_MODE_DISABLED, + CONTENT_SCALE_MODE_OBJECTS, + CONTENT_SCALE_MODE_PIXELS, + + }; + + enum ContentScaleAspect { + CONTENT_SCALE_ASPECT_IGNORE, + CONTENT_SCALE_ASPECT_KEEP, + CONTENT_SCALE_ASPECT_KEEP_WIDTH, + CONTENT_SCALE_ASPECT_KEEP_HEIGHT, + CONTENT_SCALE_ASPECT_EXPAND, + + }; + enum { + DEFAULT_WINDOW_SIZE = 100 + }; + +private: + DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID; + + String title; + mutable int current_screen = 0; + mutable Vector2i position; + mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); + mutable Size2i min_size; + mutable Size2i max_size; + mutable Mode mode = MODE_WINDOWED; + mutable bool flags[FLAG_MAX]; + bool visible = true; + bool focused = false; + + bool use_font_oversampling = false; + bool transient = false; + bool exclusive = false; + bool wrap_controls = false; + bool updating_child_controls = false; + + void _update_child_controls(); + + Size2i content_scale_size; + ContentScaleMode content_scale_mode; + ContentScaleAspect content_scale_aspect; + + void _make_window(); + void _clear_window(); + void _update_from_window(); + + void _update_viewport_size(); + void _update_window_size(); + + void _propagate_window_notification(Node *p_node, int p_notification); + + void _update_window_callbacks(); + + void _clear_transient(); + void _make_transient(); + Window *transient_parent = nullptr; + Window *exclusive_child = nullptr; + Set<Window *> transient_children; + + friend class Control; + Ref<Theme> theme; + Control *theme_owner = nullptr; + Window *theme_owner_window = nullptr; + + Viewport *embedder = nullptr; + + friend class Viewport; //friend back, can call the methods below + + void _window_input(const Ref<InputEvent> &p_ev); + void _window_input_text(const String &p_text); + void _window_drop_files(const Vector<String> &p_files); + void _rect_changed_callback(const Rect2i &p_callback); + void _event_callback(DisplayServer::WindowEvent p_event); + +protected: + Viewport *_get_embedder() const; + + virtual Rect2i _popup_adjust_rect() const { return Rect2i(); } + + virtual void _post_popup() {} + virtual Size2 _get_contents_minimum_size() const; + static void _bind_methods(); + void _notification(int p_what); + + virtual void add_child_notify(Node *p_child); + virtual void remove_child_notify(Node *p_child); + +public: + enum { + + NOTIFICATION_VISIBILITY_CHANGED = 30, + NOTIFICATION_POST_POPUP = 31, + NOTIFICATION_THEME_CHANGED = 32, + }; + + void set_title(const String &p_title); + String get_title() const; + + void set_current_screen(int p_screen); + int get_current_screen() const; + + void set_position(const Point2i &p_position); + Point2i get_position() const; + + void set_size(const Size2i &p_size); + Size2i get_size() const; + + Size2i get_real_size() const; + + void set_max_size(const Size2i &p_max_size); + Size2i get_max_size() const; + + void set_min_size(const Size2i &p_min_size); + Size2i get_min_size() const; + + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_flag(Flags p_flag, bool p_enabled); + bool get_flag(Flags p_flag) const; + + bool is_maximize_allowed() const; + + void request_attention(); + void move_to_foreground(); + + void set_visible(bool p_visible); + bool is_visible() const; + + void show(); + void hide(); + + void set_transient(bool p_transient); + bool is_transient() const; + + void set_exclusive(bool p_exclusive); + bool is_exclusive() const; + + bool can_draw() const; + + void set_ime_active(bool p_active); + void set_ime_position(const Point2i &p_pos); + + bool is_embedded() const; + + void set_content_scale_size(const Size2i &p_size); + Size2i get_content_scale_size() const; + + void set_content_scale_mode(ContentScaleMode p_mode); + ContentScaleMode get_content_scale_mode() const; + + void set_content_scale_aspect(ContentScaleAspect p_aspect); + ContentScaleAspect get_content_scale_aspect() const; + + void set_use_font_oversampling(bool p_oversampling); + bool is_using_font_oversampling() const; + + void set_wrap_controls(bool p_enable); + bool is_wrapping_controls() const; + void child_controls_changed(); + + Window *get_parent_visible_window() const; + Viewport *get_parent_viewport() const; + void popup(const Rect2i &p_rect = Rect2i()); + void popup_on_parent(const Rect2i &p_parent_rect); + void popup_centered_ratio(float p_ratio = 0.8); + void popup_centered(const Size2i &p_minsize = Size2i()); + void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75); + + void set_theme(const Ref<Theme> &p_theme); + Ref<Theme> get_theme() const; + + Size2 get_contents_minimum_size() const; + + void grab_focus(); + bool has_focus() const; + + Rect2i get_usable_parent_rect() const; + + Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; + Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; + int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + + bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + + Rect2i get_parent_rect() const; + virtual DisplayServer::WindowID get_window_id() const; + + Window(); + ~Window(); +}; + +VARIANT_ENUM_CAST(Window::Window::Mode); +VARIANT_ENUM_CAST(Window::Window::Flags); +VARIANT_ENUM_CAST(Window::ContentScaleMode); +VARIANT_ENUM_CAST(Window::ContentScaleAspect); + +#endif // WINDOW_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f15911b0e2..41c43a586b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -128,6 +128,7 @@ #include "scene/main/scene_tree.h" #include "scene/main/timer.h" #include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/audio_stream_sample.h" #include "scene/resources/bit_map.h" #include "scene/resources/box_shape.h" @@ -267,13 +268,14 @@ void register_scene_types() { ClassDB::register_class<Node>(); ClassDB::register_virtual_class<InstancePlaceholder>(); - ClassDB::register_class<Viewport>(); + ClassDB::register_virtual_class<Viewport>(); ClassDB::register_class<ViewportTexture>(); ClassDB::register_class<HTTPRequest>(); ClassDB::register_class<Timer>(); ClassDB::register_class<CanvasLayer>(); ClassDB::register_class<CanvasModulate>(); ClassDB::register_class<ResourcePreloader>(); + ClassDB::register_class<Window>(); /* REGISTER GUI */ ClassDB::register_class<ButtonGroup>(); @@ -348,8 +350,7 @@ void register_scene_types() { ClassDB::register_class<RichTextLabel>(); ClassDB::register_class<RichTextEffect>(); ClassDB::register_class<CharFXTransform>(); - ClassDB::register_class<PopupDialog>(); - ClassDB::register_class<WindowDialog>(); + ; ClassDB::register_class<AcceptDialog>(); ClassDB::register_class<ConfirmationDialog>(); ClassDB::register_class<MarginContainer>(); @@ -480,7 +481,7 @@ void register_scene_types() { #endif ClassDB::register_class<NavigationMesh>(); - AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(OS::get_singleton()->get_swap_ok_cancel()))); + AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(DisplayServer::get_singleton()->get_swap_ok_cancel()))); ClassDB::register_class<Shader>(); ClassDB::register_class<VisualShader>(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 9f5b49c4c3..0c45779307 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -188,6 +188,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Panel theme->set_stylebox("panel", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0)); + theme->set_stylebox("panel_fg", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0)); // Focus @@ -523,17 +524,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // WindowDialog - theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); - theme->set_constant("scaleborder_size", "WindowDialog", 4 * scale); + theme->set_stylebox("panel", "Window", default_style); + theme->set_stylebox("window_panel", "Window", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); + theme->set_constant("scaleborder_size", "Window", 4 * scale); - theme->set_font("title_font", "WindowDialog", large_font); - theme->set_color("title_color", "WindowDialog", Color(0, 0, 0)); - theme->set_constant("title_height", "WindowDialog", 20 * scale); + theme->set_font("title_font", "Window", large_font); + theme->set_color("title_color", "Window", Color(0, 0, 0)); + theme->set_constant("title_height", "Window", 20 * scale); + theme->set_constant("resize_margin", "Window", 4 * scale); - theme->set_icon("close", "WindowDialog", make_icon(close_png)); - theme->set_icon("close_highlight", "WindowDialog", make_icon(close_hl_png)); - theme->set_constant("close_h_ofs", "WindowDialog", 18 * scale); - theme->set_constant("close_v_ofs", "WindowDialog", 18 * scale); + theme->set_icon("close", "Window", make_icon(close_png)); + theme->set_icon("close_highlight", "Window", make_icon(close_hl_png)); + theme->set_constant("close_h_ofs", "Window", 18 * scale); + theme->set_constant("close_v_ofs", "Window", 18 * scale); // File Dialog diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 6bdc4cf6f0..75bdeeac07 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -33,7 +33,7 @@ #include "core/project_settings.h" #include "scene/2d/camera_2d.h" #include "scene/2d/visibility_notifier_2d.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "servers/physics_2d_server.h" #include "servers/visual_server.h" diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index d3c5a87cae..1f0365dab9 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -193,6 +193,12 @@ SceneStringNames::SceneStringNames() { mesh_materials[i] = "material/" + itos(i); } + _window_group = StaticCString::create("_window_group"); + _window_input = StaticCString::create("_window_input"); + window_input = StaticCString::create("window_input"); + _window_unhandled_input = StaticCString::create("_window_unhandled_input"); + + theme_changed = StaticCString::create("theme_changed"); parameters_base_path = "parameters/"; tracks_changed = "tracks_changed"; diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 7976a2072c..e255ebb3cb 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -201,6 +201,13 @@ public: StringName tracks_changed; + StringName _window_group; + StringName _window_input; + StringName _window_unhandled_input; + StringName window_input; + + StringName theme_changed; + enum { MAX_MATERIALS = 32 }; |