diff options
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r-- | scene/gui/popup_menu.cpp | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 56346f5edc..bdd0102b63 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -276,6 +276,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { } } + minsize.height = Math::ceil(minsize.height); // Ensures enough height at fractional content scales to prevent the v_scroll_bar from showing. return minsize; } @@ -312,18 +313,17 @@ int PopupMenu::_get_items_total_height() const { } int PopupMenu::_get_mouse_over(const Point2 &p_over) const { - if (p_over.x < 0 || p_over.x >= get_size().width || p_over.y < theme_cache.panel_style->get_margin(Side::SIDE_TOP)) { + float win_scale = get_content_scale_factor(); + if (p_over.x < 0 || p_over.x >= get_size().width * win_scale || p_over.y < theme_cache.panel_style->get_margin(Side::SIDE_TOP) * win_scale) { return -1; } - Point2 ofs; + Point2 ofs = Point2(0, theme_cache.v_separation * 0.5) * win_scale; for (int i = 0; i < items.size(); i++) { - ofs.y += theme_cache.v_separation; - - ofs.y += _get_item_height(i); - - if (p_over.y - control->get_position().y < ofs.y) { + ofs.y += i > 0 ? (float)theme_cache.v_separation * win_scale : (float)theme_cache.v_separation * win_scale * 0.5; + ofs.y += _get_item_height(i) * win_scale; + if (p_over.y - control->get_position().y * win_scale < ofs.y) { return i; } } @@ -341,15 +341,17 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { Rect2 this_rect(this_pos, get_size()); float scroll_offset = control->get_position().y; + float scaled_ofs_cache = items[p_over]._ofs_cache * get_content_scale_factor(); + float scaled_height_cache = items[p_over]._height_cache * get_content_scale_factor(); submenu_popup->reset_size(); // Shrink the popup size to its contents. Size2 submenu_size = submenu_popup->get_size(); Point2 submenu_pos; if (control->is_layout_rtl()) { - submenu_pos = this_pos + Point2(-submenu_size.width, items[p_over]._ofs_cache + scroll_offset - theme_cache.v_separation / 2); + submenu_pos = this_pos + Point2(-submenu_size.width, scaled_ofs_cache + scroll_offset - theme_cache.v_separation / 2); } else { - submenu_pos = this_pos + Point2(this_rect.size.width, items[p_over]._ofs_cache + scroll_offset - theme_cache.v_separation / 2); + submenu_pos = this_pos + Point2(this_rect.size.width, scaled_ofs_cache + scroll_offset - theme_cache.v_separation / 2); } // Fix pos if going outside parent rect. @@ -386,8 +388,8 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { // Set autohide areas. Rect2 safe_area = this_rect; - safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2; - safe_area.size.y = items[p_over]._height_cache + theme_cache.v_separation; + safe_area.position.y += scaled_ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2; + safe_area.size.y = scaled_height_cache + theme_cache.v_separation; Viewport *vp = submenu_popup->get_embedder(); if (vp) { vp->subwindow_set_popup_safe_rect(submenu_popup, safe_area); @@ -400,11 +402,11 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { // Autohide area above the submenu item. submenu_pum->clear_autohide_areas(); - submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2)); + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, scaled_ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2)); // If there is an area below the submenu item, add an autohide area there. - if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) { - int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + theme_cache.v_separation / 2 + theme_cache.panel_style->get_offset().height; + if (scaled_ofs_cache + scaled_height_cache + scroll_offset <= control->get_size().height) { + int from = scaled_ofs_cache + scaled_height_cache + scroll_offset + theme_cache.v_separation / 2 + theme_cache.panel_style->get_offset().height; submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from)); } } @@ -576,6 +578,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) { } item_clickable_area.size.width -= scroll_container->get_v_scroll_bar()->get_size().width; } + item_clickable_area.size = item_clickable_area.size * get_content_scale_factor(); Ref<InputEventMouseButton> b = p_event; @@ -640,11 +643,17 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) { for (const Rect2 &E : autohide_areas) { if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E.has_point(m->get_position())) { + // The mouse left the safe area, prepare to close. _close_pressed(); return; } } + if (!minimum_lifetime_timer->is_stopped()) { + // The mouse left the safe area, but came back again, so cancel the auto-closing. + minimum_lifetime_timer->stop(); + } + if (!item_clickable_area.has_point(m->get_position())) { return; } @@ -1005,9 +1014,6 @@ void PopupMenu::_notification(int p_what) { float pm_delay = pm->get_submenu_popup_delay(); set_submenu_popup_delay(pm_delay); } - if (!is_embedded()) { - set_flag(FLAG_NO_FOCUS, true); - } if (system_menu_id != NativeMenu::INVALID_MENU_ID) { bind_global_menu(); } @@ -2799,6 +2805,7 @@ void PopupMenu::_bind_methods() { Item defaults(true); base_property_helper.set_prefix("item_"); + base_property_helper.set_array_length_getter(&PopupMenu::get_item_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "text"), defaults.text, &PopupMenu::set_item_text, &PopupMenu::get_item_text); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &PopupMenu::set_item_icon, &PopupMenu::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::INT, "checkable", PROPERTY_HINT_ENUM, "No,As checkbox,As radio button"), defaults.checkable_type, &PopupMenu::_set_item_checkable_type, &PopupMenu::_get_item_checkable_type); @@ -2819,8 +2826,18 @@ void PopupMenu::popup(const Rect2i &p_bounds) { if (native) { NativeMenu::get_singleton()->popup(global_menu, (p_bounds != Rect2i()) ? p_bounds.position : get_position()); } else { + set_flag(FLAG_NO_FOCUS, !is_embedded()); + moved = Vector2(); popup_time_msec = OS::get_singleton()->get_ticks_msec(); + if (!is_embedded()) { + float win_scale = get_parent_visible_window()->get_content_scale_factor(); + set_content_scale_factor(win_scale); + Size2 minsize = get_contents_minimum_size() * win_scale; + minsize.height = Math::ceil(minsize.height); // Ensures enough height at fractional content scales to prevent the v_scroll_bar from showing. + set_min_size(minsize); // `height` is truncated here by the cast to Size2i for Window.min_size. + set_size(Vector2(0, 0)); // Shrinkwraps to min size. + } Popup::popup(p_bounds); } } @@ -2838,6 +2855,8 @@ void PopupMenu::set_visible(bool p_visible) { NativeMenu::get_singleton()->popup(global_menu, get_position()); } } else { + set_flag(FLAG_NO_FOCUS, !is_embedded()); + Popup::set_visible(p_visible); } } @@ -2856,7 +2875,7 @@ PopupMenu::PopupMenu() { control->set_h_size_flags(Control::SIZE_EXPAND_FILL); control->set_v_size_flags(Control::SIZE_EXPAND_FILL); scroll_container->add_child(control, false, INTERNAL_MODE_FRONT); - control->connect("draw", callable_mp(this, &PopupMenu::_draw_items)); + control->connect(SceneStringName(draw), callable_mp(this, &PopupMenu::_draw_items)); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); |