diff options
25 files changed, 325 insertions, 94 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 766df27e62..182b406705 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2471,6 +2471,7 @@ void AnimationTrackEdit::_path_entered(const String &p_text) { undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text); undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track)); undo_redo->commit_action(); + path_popup->hide(); } bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const { @@ -2843,20 +2844,20 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && clicking_on_name) { if (!path) { + path_popup = memnew(Popup); + path_popup->set_wrap_controls(true); + add_child(path_popup); path = memnew(LineEdit); - add_child(path); - path->set_as_toplevel(true); + path_popup->add_child(path); + path->set_anchors_and_margins_preset(PRESET_WIDE); path->connect("text_entered", callable_mp(this, &AnimationTrackEdit::_path_entered)); } path->set_text(animation->track_get_path(track)); Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset(); - path->set_position(get_global_position() + path_rect.position - theme_ofs); - path->set_size(path_rect.size); -#ifndef _MSC_VER -#warning show modal not supported any longer, need to move this to a popup -#endif - path->show(); + path_popup->set_position(get_screen_position() + path_rect.position - theme_ofs); + path_popup->set_size(path_rect.size); + path_popup->popup(); path->grab_focus(); path->set_cursor_position(path->get_text().length()); clicking_on_name = false; @@ -3093,6 +3094,7 @@ AnimationTrackEdit::AnimationTrackEdit() { timeline = NULL; root = NULL; path = NULL; + path_popup = NULL; menu = NULL; clicking_on_name = false; dropping_at = 0; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 8de56a153e..7f13716b67 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -140,6 +140,7 @@ class AnimationTrackEdit : public Control { }; AnimationTimelineEdit *timeline; UndoRedo *undo_redo; + Popup *path_popup; LineEdit *path; Node *root; Control *play_position; //separate control used to draw so updates for only position changed are much faster diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 11683c00e7..2c115c66cb 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -273,7 +273,7 @@ void EditorSpinSlider::_notification(int p_what) { Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE); draw_rect(grabber_rect, c); - bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input->is_visible(); + bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input_popup->is_visible(); if (grabber->is_visible() != display_grabber) { if (display_grabber) { grabber->show(); @@ -371,7 +371,7 @@ void EditorSpinSlider::_evaluate_input_text() { //text_entered signal void EditorSpinSlider::_value_input_entered(const String &p_text) { value_input_just_closed = true; - value_input->hide(); + value_input_popup->hide(); } //modal_closed signal @@ -394,7 +394,7 @@ void EditorSpinSlider::_value_focus_exited() { // -> modal_close was not called // -> need to close/hide manually if (!value_input_just_closed) { //value_input_just_closed should do the same - value_input->hide(); + value_input_popup->hide(); //tab was pressed } else { //enter, click, esc @@ -437,11 +437,11 @@ void EditorSpinSlider::set_custom_label_color(bool p_use_custom_label_color, Col } void EditorSpinSlider::_focus_entered() { - Rect2 gr = get_global_rect(); + Rect2 gr = get_screen_rect(); value_input->set_text(get_text_value()); - value_input->set_position(gr.position); - value_input->set_size(gr.size); - value_input->call_deferred("show_modal"); + value_input_popup->set_position(gr.position); + value_input_popup->set_size(gr.size); + value_input_popup->call_deferred("popup"); value_input->call_deferred("grab_focus"); value_input->call_deferred("select_all"); value_input->set_focus_next(find_next_valid_focus()->get_path()); @@ -488,11 +488,13 @@ EditorSpinSlider::EditorSpinSlider() { mousewheel_over_grabber = false; grabbing_grabber = false; grabber_range = 1; + value_input_popup = memnew(Popup); + add_child(value_input_popup); value_input = memnew(LineEdit); - add_child(value_input); - value_input->set_as_toplevel(true); - value_input->hide(); - value_input->connect("modal_closed", callable_mp(this, &EditorSpinSlider::_value_input_closed)); + value_input_popup->add_child(value_input); + value_input_popup->set_wrap_controls(true); + value_input->set_anchors_and_margins_preset(PRESET_WIDE); + value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); value_input->connect("text_entered", callable_mp(this, &EditorSpinSlider::_value_input_entered)); value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); value_input_just_closed = false; diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index 81a7b981cc..db74f5fb70 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -62,6 +62,7 @@ class EditorSpinSlider : public Range { Vector2 grabbing_spinner_mouse_pos; double pre_grab_value; + Popup *value_input_popup; LineEdit *value_input; bool value_input_just_closed; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index c5979bf952..8ff8c92f4d 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -155,14 +155,10 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv edit_rect.position -= line_sb->get_offset(); edit_rect.size += line_sb->get_minimum_size(); - name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); - name_edit->set_size(edit_rect.size); + name_edit_popup->set_position(state_machine_draw->get_screen_transform().xform(edit_rect.position)); + name_edit_popup->set_size(edit_rect.size); name_edit->set_text(node_rects[i].node_name); -#ifndef _MSC_VER -#warning no more show modal, so it must replaced by a popup -#endif - //name_edit->show_modal(); - name_edit->show(); + name_edit_popup->popup(); name_edit->grab_focus(); name_edit->select_all(); @@ -1114,7 +1110,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); - name_edit->hide(); + name_edit_popup->hide(); updating = false; state_machine_draw->update(); @@ -1361,12 +1357,14 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { animations_menu->set_name("animations"); animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_animation_type)); + name_edit_popup = memnew(Popup); + add_child(name_edit_popup); name_edit = memnew(LineEdit); - state_machine_draw->add_child(name_edit); - name_edit->hide(); + name_edit_popup->add_child(name_edit); + name_edit->set_anchors_and_margins_preset(PRESET_WIDE); + name_edit_popup->add_child(name_edit); name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); - name_edit->set_as_toplevel(true); open_file = memnew(EditorFileDialog); add_child(open_file); diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 132e66b28d..5c4fc87df5 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -50,6 +50,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { ToolButton *tool_select; ToolButton *tool_create; ToolButton *tool_connect; + Popup *name_edit_popup; LineEdit *name_edit; HBoxContainer *tool_erase_hb; diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 701ad0e263..8e225d9b5d 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -563,8 +563,12 @@ Point2i DisplayServerX11::screen_get_position(int p_screen) const { return position; } + Size2i DisplayServerX11::screen_get_size(int p_screen) const { + return screen_get_usable_rect(p_screen).size; +} +Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -574,16 +578,17 @@ Size2i DisplayServerX11::screen_get_size(int p_screen) const { // Using Xinerama Extension int event_base, error_base; const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); - if (!ext_okay) return Size2i(0, 0); + if (!ext_okay) return Rect2i(0, 0, 0, 0); int count; XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); - if (p_screen >= count) return Size2i(0, 0); + if (p_screen >= count) return Rect2i(0, 0, 0, 0); - Size2i size = Point2i(xsi[p_screen].width, xsi[p_screen].height); + Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height); XFree(xsi); - return size; + return rect; } + int DisplayServerX11::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index c7d9b8f0d9..bfce4dc88a 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -259,6 +259,7 @@ public: virtual int get_screen_count() const; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 9696e71630..3f0c565277 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -125,7 +125,10 @@ void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) { } } Point2i DisplayServerWindows::mouse_get_position() const { - return Point2(old_x, old_y); + POINT p; + GetCursorPos(&p); + return Point2i(p.x, p.y); + //return Point2(old_x, old_y); } int DisplayServerWindows::mouse_get_button_state() const { return last_button_state; @@ -280,6 +283,12 @@ typedef struct { Size2 size; } EnumSizeData; +typedef struct { + int count; + int screen; + Rect2i rect; +} EnumRectData; + static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { EnumSizeData *data = (EnumSizeData *)dwData; @@ -301,6 +310,34 @@ Size2i DisplayServerWindows::screen_get_size(int p_screen) const { return data.size; } +static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { + + EnumRectData *data = (EnumRectData *)dwData; + if (data->count == data->screen) { + MONITORINFO minfo; + zeromem(&minfo, sizeof(MONITORINFO)); + minfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfoA(hMonitor, &minfo); + + data->rect.position.x = minfo.rcWork.left; + data->rect.position.y = minfo.rcWork.top; + data->rect.size.x = minfo.rcWork.right - minfo.rcWork.left; + data->rect.size.y = minfo.rcWork.bottom - minfo.rcWork.top; + } + + data->count++; + return TRUE; +} + +Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const { + + _THREAD_SAFE_METHOD_ + + EnumRectData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Rect2i() }; + EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcUsableSize, (LPARAM)&data); + return data.rect; +} + typedef struct { int count; int screen; @@ -691,6 +728,7 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo wd.width = w; wd.height = h; + #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { context_vulkan->window_resize(p_window, w, h); @@ -2232,8 +2270,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_MOVE: { if (!IsIconic(windows[window_id].hWnd)) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); + int x = int16_t(LOWORD(lParam)); + int y = int16_t(HIWORD(lParam)); windows[window_id].last_pos = Point2(x, y); if (!windows[window_id].rect_changed_callback.is_null()) { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 70878ae0dc..b300ae74b5 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -280,6 +280,7 @@ public: virtual int get_screen_count() const; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 948e46b649..2ec9bb2292 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -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))); @@ -884,8 +887,32 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { _update_picker(); - popup->set_position(get_screen_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(); } @@ -961,7 +988,9 @@ 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)); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index bfaace69d7..14bca0e2c8 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -625,7 +625,7 @@ void Control::_notification(int p_notification) { get_viewport()->_gui_hid_control(this); //remove key focus - //remove modalness + } else { data.minimum_size_valid = false; _size_changed(); @@ -2117,9 +2117,6 @@ void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_o Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr; - if (c && c != p_owner && c->data.theme.is_valid()) // has a theme, this can't be propagated - return; - if (w && w != p_owner_window && w->theme.is_valid()) // has a theme, this can't be propagated return; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 61441ff958..ba1f651b5c 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -63,6 +63,7 @@ void MenuButton::pressed() { popup->set_size(Size2(size.width, 0)); popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size())); + popup->take_mouse_focus(); popup->popup(); } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 4ed87ff42f..77843262e1 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -42,6 +42,7 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) { } void Popup::_parent_focused() { + _close_pressed(); } void Popup::_notification(int p_what) { @@ -72,6 +73,7 @@ void Popup::_notification(int p_what) { } break; case NOTIFICATION_WM_CLOSE_REQUEST: { _close_pressed(); + } break; } } @@ -101,6 +103,35 @@ void Popup::_bind_methods() { ADD_SIGNAL(MethodInfo("popup_hide")); } +Rect2i Popup::_popup_adjust_rect() const { + ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); + Rect2i parent = get_usable_parent_rect(); + + if (parent == Rect2i()) { + return Rect2i(); + } + + Rect2i current(get_position(), get_size()); + + 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; + } + + if (current.position.x < parent.position.x) { + current.position.x = parent.position.x; + } + + 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; + } + + if (current.position.y < parent.position.y) { + current.position.y = parent.position.y; + } + + return current; +} + Popup::Popup() { parent_visible = nullptr; @@ -166,7 +197,9 @@ void PopupPanel::_update_child_rects() { void PopupPanel::_notification(int p_what) { - if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) { + if (p_what == NOTIFICATION_THEME_CHANGED) { + panel->add_theme_style_override("panel", get_theme_stylebox("panel", "PopupPanel")); + } else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) { panel->add_theme_style_override("panel", get_theme_stylebox("panel", "PopupPanel")); _update_child_rects(); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 20b355bc18..6cd2b4028f 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -41,9 +41,11 @@ class Popup : public Window { void _input_from_window(const Ref<InputEvent> &p_event); void _parent_focused(); - void _close_pressed(); protected: + void _close_pressed(); + virtual Rect2i _popup_adjust_rect() const; + void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index e325f2661a..c096dc94cb 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -185,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); @@ -196,17 +199,24 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { int vseparation = get_theme_constant("vseparation"); Ref<Font> font = get_theme_font("font"); - float dy = (vseparation + font->get_height()) * 3 * p_factor; + Rect2 visible_rect = get_usable_parent_rect(); + + int dy = (vseparation + font->get_height()) * 3 * p_factor; if (dy > 0) { const float global_top = get_position().y; - const float limit = global_top < 0 ? -global_top : 0; + 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_position().y + get_size().y; - const float viewport_height = get_parent_rect().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; @@ -295,15 +305,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { case BUTTON_WHEEL_DOWN: { - if (get_position().y + get_size().y > get_parent_rect().size.y) { - _scroll(-b->get_factor(), b->get_position()); - } + _scroll(-b->get_factor(), b->get_position()); } break; case BUTTON_WHEEL_UP: { - if (get_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 @@ -355,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; } } @@ -382,9 +389,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { - if (get_position().y + get_size().y > get_parent_rect().size.y || get_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; @@ -578,7 +583,7 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_WM_MOUSE_ENTER: { - grab_focus(); + //grab_focus(); } break; case NOTIFICATION_WM_MOUSE_EXIT: { @@ -595,6 +600,21 @@ void PopupMenu::_notification(int p_what) { case NOTIFICATION_WM_SIZE_CHANGED: { } 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: { if (!is_visible()) { @@ -617,6 +637,12 @@ void PopupMenu::_notification(int p_what) { pm->hide(); } + + set_process_internal(false); + } else { + if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + set_process_internal(true); + } } } break; } @@ -1366,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); @@ -1473,7 +1507,7 @@ PopupMenu::PopupMenu() { add_child(control); control->set_anchors_and_margins_preset(Control::PRESET_WIDE); - control->connect("gui_input", callable_mp(this, &PopupMenu::_gui_input)); + connect("window_input", callable_mp(this, &PopupMenu::_gui_input)); control->connect("draw", callable_mp(this, &PopupMenu::_draw)); mouse_over = -1; diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 511c630ad2..2eef1f009d 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -215,6 +215,8 @@ public: virtual void popup(const Rect2 &p_bounds = Rect2()); + void take_mouse_focus(); + PopupMenu(); ~PopupMenu(); }; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 38ae1f36bc..653ac74164 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -38,6 +38,8 @@ #include "core/project_settings.h" #include "scene/main/window.h" +#include "box_container.h" + #ifdef TOOLS_ENABLED #include "editor/editor_scale.h" #endif @@ -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; @@ -2806,22 +2807,22 @@ 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)); -#ifndef _MSC_VER -#warning show modal no longer works, need to replace by a popup -#endif + popup_rect.size.y += value_editor->get_minimum_size().height; + value_editor->show(); updating_value_editor = true; value_editor->set_min(c.min); @@ -2830,12 +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(); } -#ifndef _MSC_VER -#warning show modal no longer works, need to replace by a popup -#endif - text_editor->show(); + + 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; } @@ -4026,13 +4032,22 @@ Tree::Tree() { popup_menu->hide(); add_child(popup_menu); // 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); @@ -4047,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/main/viewport.cpp b/scene/main/viewport.cpp index 0dcb013c37..b809dc4d3a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -191,6 +191,7 @@ Viewport::GUI::GUI() { dragging = false; mouse_focus = NULL; + forced_mouse_focus = false; mouse_click_grabber = NULL; mouse_focus_mask = 0; key_focus = NULL; @@ -595,6 +596,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); @@ -847,8 +849,7 @@ void Viewport::_notification(int p_what) { _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; @@ -1107,7 +1108,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()); @@ -1984,6 +1987,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()) { @@ -2029,6 +2033,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 { @@ -2427,6 +2432,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) { @@ -2481,6 +2487,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++) { @@ -3234,6 +3241,22 @@ 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_world_2d", "world_2d"), &Viewport::set_world_2d); @@ -3465,6 +3488,7 @@ 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; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 08dd505161..5065ebef1a 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -302,6 +302,7 @@ private: 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; @@ -555,6 +556,9 @@ public: bool is_embedding_subwindows() const; Viewport *get_parent_viewport() const; + + void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control); + Viewport(); ~Viewport(); }; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 4ea00a4187..4b5710e8a4 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -35,6 +35,7 @@ #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; @@ -207,8 +208,8 @@ void Window::set_ime_position(const Point2i &p_pos) { bool Window::is_embedded() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - Viewport *parent_vp = get_parent_viewport(); - return parent_vp && parent_vp->is_embedding_subwindows(); + + return _get_embedder() != nullptr; } void Window::_make_window() { @@ -1027,6 +1028,12 @@ void Window::popup(const Rect2 &p_screen_rect) { 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(); @@ -1049,6 +1056,24 @@ 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(); + print_line("using embedded " + parent); + } 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())); + print_line("using windowid " + parent); + } + return parent; +} + void Window::add_child_notify(Node *p_child) { Control *child_c = Object::cast_to<Control>(p_child); @@ -1292,6 +1317,12 @@ void Window::_bind_methods() { 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"); diff --git a/scene/main/window.h b/scene/main/window.h index 04c077a550..77bbfec8d8 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -108,8 +108,6 @@ private: void _propagate_window_notification(Node *p_node, int p_notification); - virtual DisplayServer::WindowID get_window_id() const; - void _update_window_callbacks(); void _clear_transient(); @@ -123,8 +121,6 @@ private: Control *theme_owner = nullptr; Window *theme_owner_window = nullptr; - Viewport *_get_embedder() const; - Viewport *embedder = nullptr; friend class Viewport; //friend back, can call the methods below @@ -136,6 +132,10 @@ private: 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(); @@ -234,6 +234,8 @@ public: 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; @@ -249,6 +251,7 @@ public: 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(); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index efa3c8af7b..d5d41948c6 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -252,6 +252,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count); ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW)); + ClassDB::bind_method(D_METHOD("screen_get_usable_rect", "screen"), &DisplayServer::screen_get_usable_rect, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_dpi", "screen"), &DisplayServer::screen_get_dpi, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW)); diff --git a/servers/display_server.h b/servers/display_server.h index dfa98e350f..d351f0e322 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -140,6 +140,7 @@ public: virtual int get_screen_count() const = 0; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; enum ScreenOrientation { |