diff options
Diffstat (limited to 'scene/main/viewport.cpp')
-rw-r--r-- | scene/main/viewport.cpp | 760 |
1 files changed, 506 insertions, 254 deletions
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 50d0520d4b..0dcb013c37 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -187,6 +187,7 @@ public: Viewport::GUI::GUI() { embed_subwindows_hint = false; + embedding_subwindows = false; dragging = false; mouse_focus = NULL; @@ -198,8 +199,6 @@ Viewport::GUI::GUI() { tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; - subwindow_visibility_dirty = false; - subwindow_order_dirty = false; } ///////////////////////////////////// @@ -236,6 +235,180 @@ 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 (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()); @@ -263,6 +436,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()); @@ -297,7 +472,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 @@ -358,6 +532,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: { @@ -1318,25 +1493,16 @@ 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); + return ev->xformed_by(ai); } Vector2 Viewport::get_mouse_position() const { - return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(InputFilter::get_singleton()->get_mouse_position() - _get_window_offset()); + return gui.last_mouse_pos; } void Viewport::warp_mouse(const Vector2 &p_pos) { @@ -1345,40 +1511,6 @@ void Viewport::warp_mouse(const Vector2 &p_pos) { InputFilter::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>(); -} - void Viewport::_gui_sort_roots() { if (!gui.roots_order_dirty) @@ -1581,26 +1713,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()) { @@ -1629,8 +1742,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 @@ -1735,39 +1846,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; @@ -1990,15 +2068,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)) { - over = NULL; //nothing can be found outside the modal stack - } - } - if (over != gui.mouse_over) { if (gui.mouse_over) { @@ -2039,11 +2108,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { 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) { @@ -2122,14 +2186,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 @@ -2195,14 +2251,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(); @@ -2246,21 +2294,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 @@ -2319,61 +2352,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."); @@ -2410,21 +2392,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) { @@ -2485,11 +2452,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; @@ -2561,22 +2523,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; @@ -2647,10 +2593,317 @@ void Viewport::_post_gui_grab_click_focus() { 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(gui.subwindow_focused, 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()); @@ -2671,6 +2924,11 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { 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", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input } @@ -2782,11 +3040,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; } @@ -2800,10 +3053,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) { @@ -3039,12 +3288,9 @@ void Viewport::_bind_methods() { 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); @@ -3157,13 +3403,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)); @@ -3227,6 +3466,8 @@ Viewport::Viewport() { gui.roots_order_dirty = false; gui.mouse_focus = NULL; gui.last_mouse_focus = NULL; + gui.subwindow_focused = nullptr; + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; msaa = MSAA_DISABLED; @@ -3302,6 +3543,16 @@ 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); @@ -3323,6 +3574,7 @@ void SubViewport::_bind_methods() { 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); |