summaryrefslogtreecommitdiffstats
path: root/scene/gui/popup_menu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r--scene/gui/popup_menu.cpp57
1 files changed, 38 insertions, 19 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 25d999851b..bdd0102b63 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -92,7 +92,7 @@ RID PopupMenu::bind_global_menu() {
NativeMenu *nmenu = NativeMenu::get_singleton();
- if (system_menu_id != NativeMenu::INVALID_MENU_ID) {
+ if (system_menu_id != NativeMenu::INVALID_MENU_ID && nmenu->has_system_menu(system_menu_id)) {
if (system_menus.has(system_menu_id)) {
WARN_PRINT(vformat("Attempting to bind PopupMenu to the system menu %s, but another menu is already bound to it. This menu: %s, current menu: %s", nmenu->get_system_menu_name(system_menu_id), get_description(), system_menus[system_menu_id]->get_description()));
global_menu = nmenu->create_menu();
@@ -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);