feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -316,32 +316,26 @@ int PopupMenu::_get_items_total_height() const {
}
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
// Make the item area exclude shadows and the vertical margins and scrollbar.
Rect2 item_clickable_area = panel->get_global_rect();
if (scroll_container->get_v_scroll_bar()->is_visible_in_tree()) {
const int scroll_width = scroll_container->get_v_scroll_bar()->get_size().width;
if (is_layout_rtl()) {
item_clickable_area.position.x += scroll_width;
item_clickable_area.size.width -= scroll_width;
}
item_clickable_area.size.width -= scroll_width;
}
float win_scale = get_content_scale_factor();
item_clickable_area.position.x += theme_cache.panel_style->get_margin(SIDE_LEFT);
item_clickable_area.position.y += theme_cache.panel_style->get_margin(SIDE_TOP);
item_clickable_area.position *= win_scale;
item_clickable_area.size.y -= theme_cache.panel_style->get_margin(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_BOTTOM);
item_clickable_area.size *= win_scale;
// Transform to scroll_container local coordinates.
const Point2 scaled_pos = p_over / get_content_scale_factor();
const Point2 over_scroll_container =
scroll_container->get_global_transform_with_canvas().xform_inv(scaled_pos);
if (!item_clickable_area.has_point(p_over)) {
// Check if point is inside the item control as clipped by scroll_container.
const Rect2 scroll_container_rect = Rect2(Point2(), scroll_container->get_size());
const Rect2 bounding_rect = scroll_container_rect.intersection(control->get_rect());
if (!bounding_rect.has_point(over_scroll_container)) {
return -1;
}
float ofs = item_clickable_area.position.y + (float)theme_cache.v_separation * win_scale * 0.5;
// Perform item hit check in control node local space,
// so we don't need to worry about any of the container theming.
const float over_control_y = control->get_transform().xform_inv(over_scroll_container).y;
float bottom_edge = 0;
for (int i = 0; i < items.size(); i++) {
ofs += i > 0 ? (float)theme_cache.v_separation * win_scale : (float)theme_cache.v_separation * win_scale * 0.5;
ofs += _get_item_height(i) * win_scale;
if (p_over.y - control->get_position().y * win_scale < ofs) {
bottom_edge += theme_cache.v_separation;
bottom_edge += _get_item_height(i);
if (bottom_edge > over_control_y) {
return i;
}
}
@ -499,9 +493,11 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
bool match_found = false;
for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
prev_mouse_over = mouse_over;
mouse_over = i;
emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
queue_accessibility_update();
control->queue_redraw();
set_input_as_handled();
match_found = true;
@ -513,9 +509,11 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
// If the last item is not selectable, try re-searching from the start.
for (int i = 0; i < search_from; i++) {
if (!items[i].separator && !items[i].disabled) {
prev_mouse_over = mouse_over;
mouse_over = i;
emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
queue_accessibility_update();
control->queue_redraw();
set_input_as_handled();
break;
@ -537,9 +535,11 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
bool match_found = false;
for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
prev_mouse_over = mouse_over;
mouse_over = i;
emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
queue_accessibility_update();
control->queue_redraw();
set_input_as_handled();
match_found = true;
@ -551,9 +551,11 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
// If the first item is not selectable, try re-searching from the end.
for (int i = items.size() - 1; i >= search_from; i--) {
if (!items[i].separator && !items[i].disabled) {
prev_mouse_over = mouse_over;
mouse_over = i;
emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
queue_accessibility_update();
control->queue_redraw();
set_input_as_handled();
break;
@ -738,9 +740,11 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
}
if (items[i].text.findn(search_string) == 0) {
prev_mouse_over = mouse_over;
mouse_over = i;
emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
queue_accessibility_update();
control->queue_redraw();
set_input_as_handled();
break;
@ -755,6 +759,7 @@ void PopupMenu::_mouse_over_update(const Point2 &p_over) {
if (id < 0) {
mouse_over = -1;
queue_accessibility_update();
control->queue_redraw();
return;
}
@ -766,6 +771,7 @@ void PopupMenu::_mouse_over_update(const Point2 &p_over) {
if (over != mouse_over) {
mouse_over = over;
queue_accessibility_update();
control->queue_redraw();
}
}
@ -1060,7 +1066,7 @@ Rect2i PopupMenu::_popup_adjust_rect() const {
_update_shadow_offsets();
if (is_layout_rtl()) {
current.position -= Vector2(ABS(panel->get_offset(SIDE_RIGHT)), panel->get_offset(SIDE_TOP)) * get_content_scale_factor();
current.position -= Vector2(Math::abs(panel->get_offset(SIDE_RIGHT)), panel->get_offset(SIDE_TOP)) * get_content_scale_factor();
} else {
current.position -= Vector2(panel->get_offset(SIDE_LEFT), panel->get_offset(SIDE_TOP)) * get_content_scale_factor();
}
@ -1104,8 +1110,105 @@ void PopupMenu::remove_child_notify(Node *p_child) {
_menu_changed();
}
void PopupMenu::_accessibility_action_click(const Variant &p_data, int p_idx) {
activate_item(p_idx);
}
RID PopupMenu::get_focused_accessibility_element() const {
if (mouse_over == -1) {
return get_accessibility_element();
} else {
const Item &item = items[mouse_over];
return item.accessibility_item_element;
}
}
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_EXIT_TREE: {
if (system_menu_id != NativeMenu::INVALID_MENU_ID) {
unbind_global_menu();
}
[[fallthrough]];
}
case NOTIFICATION_ACCESSIBILITY_INVALIDATE: {
for (int i = 0; i < items.size(); i++) {
items.write[i].accessibility_item_element = RID();
}
accessibility_scroll_element = RID();
} break;
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
if (has_meta("_menu_name")) {
DisplayServer::get_singleton()->accessibility_update_set_name(ae, get_meta("_menu_name", get_name()));
}
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_MENU);
DisplayServer::get_singleton()->accessibility_update_set_list_item_count(ae, items.size());
if (accessibility_scroll_element.is_null()) {
accessibility_scroll_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_CONTAINER);
}
Transform2D scroll_xform;
scroll_xform.set_origin(Vector2i(0, -scroll_container->get_v_scroll_bar()->get_value()));
DisplayServer::get_singleton()->accessibility_update_set_transform(accessibility_scroll_element, scroll_xform);
DisplayServer::get_singleton()->accessibility_update_set_bounds(accessibility_scroll_element, Rect2(0, 0, get_size().x, scroll_container->get_v_scroll_bar()->get_max()));
float scroll_width = scroll_container->get_v_scroll_bar()->is_visible_in_tree() ? scroll_container->get_v_scroll_bar()->get_size().width : 0;
float display_width = control->get_size().width - scroll_width;
Point2 ofs;
for (int i = 0; i < items.size(); i++) {
const Item &item = items.write[i];
ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
Point2 item_ofs = ofs;
if (item.accessibility_item_element.is_null()) {
item.accessibility_item_element = DisplayServer::get_singleton()->accessibility_create_sub_element(accessibility_scroll_element, DisplayServer::AccessibilityRole::ROLE_MENU_ITEM);
item.accessibility_item_dirty = true;
}
item_ofs.x += item.indent * theme_cache.indent;
float h = _get_item_height(i);
if (item.accessibility_item_dirty || i == prev_mouse_over || i == mouse_over) {
switch (item.checkable_type) {
case Item::CHECKABLE_TYPE_NONE: {
DisplayServer::get_singleton()->accessibility_update_set_role(item.accessibility_item_element, DisplayServer::AccessibilityRole::ROLE_MENU_ITEM);
} break;
case Item::CHECKABLE_TYPE_CHECK_BOX: {
DisplayServer::get_singleton()->accessibility_update_set_role(item.accessibility_item_element, DisplayServer::AccessibilityRole::ROLE_MENU_ITEM_CHECK_BOX);
DisplayServer::get_singleton()->accessibility_update_set_checked(item.accessibility_item_element, item.checked);
} break;
case Item::CHECKABLE_TYPE_RADIO_BUTTON: {
DisplayServer::get_singleton()->accessibility_update_set_role(item.accessibility_item_element, DisplayServer::AccessibilityRole::ROLE_MENU_ITEM_RADIO);
DisplayServer::get_singleton()->accessibility_update_set_checked(item.accessibility_item_element, item.checked);
} break;
}
DisplayServer::get_singleton()->accessibility_update_add_action(item.accessibility_item_element, DisplayServer::AccessibilityAction::ACTION_CLICK, callable_mp(this, &PopupMenu::_accessibility_action_click).bind(i));
DisplayServer::get_singleton()->accessibility_update_set_list_item_index(item.accessibility_item_element, i);
DisplayServer::get_singleton()->accessibility_update_set_list_item_level(item.accessibility_item_element, 0);
DisplayServer::get_singleton()->accessibility_update_set_list_item_selected(item.accessibility_item_element, i == mouse_over);
DisplayServer::get_singleton()->accessibility_update_set_name(item.accessibility_item_element, item.xl_text);
DisplayServer::get_singleton()->accessibility_update_set_flag(item.accessibility_item_element, DisplayServer::AccessibilityFlags::FLAG_DISABLED, item.disabled);
DisplayServer::get_singleton()->accessibility_update_set_tooltip(item.accessibility_item_element, item.tooltip);
DisplayServer::get_singleton()->accessibility_update_set_bounds(item.accessibility_item_element, Rect2(item_ofs, Size2(display_width, h + theme_cache.v_separation)));
item.accessibility_item_dirty = false;
}
ofs.y += h;
}
prev_mouse_over = -1;
} break;
case NOTIFICATION_ENTER_TREE: {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
if (pm) {
@ -1118,12 +1221,6 @@ void PopupMenu::_notification(int p_what) {
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (system_menu_id != NativeMenu::INVALID_MENU_ID) {
unbind_global_menu();
}
} break;
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
panel->add_theme_style_override(SceneStringName(panel), theme_cache.panel_style);
@ -1146,12 +1243,14 @@ void PopupMenu::_notification(int p_what) {
}
for (int i = 0; i < items.size(); i++) {
Item &item = items.write[i];
item.xl_text = atr(item.text);
item.xl_text = _atr(i, item.text);
item.dirty = true;
if (is_global) {
nmenu->set_item_text(global_menu, i, item.xl_text);
}
item.accessibility_item_dirty = true;
_shape_item(i);
queue_accessibility_update();
}
child_controls_changed();
@ -1166,6 +1265,7 @@ void PopupMenu::_notification(int p_what) {
case NOTIFICATION_WM_MOUSE_EXIT: {
if (mouse_over >= 0 && (!items[mouse_over].submenu || submenu_over != -1)) {
mouse_over = -1;
queue_accessibility_update();
control->queue_redraw();
}
} break;
@ -1281,7 +1381,9 @@ void PopupMenu::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
if (mouse_over >= 0) {
prev_mouse_over = mouse_over;
mouse_over = -1;
queue_accessibility_update();
control->queue_redraw();
}
@ -1341,6 +1443,7 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) {
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1364,6 +1467,7 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1387,6 +1491,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1412,6 +1517,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1435,6 +1541,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1460,6 +1567,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1485,6 +1593,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1522,6 +1631,7 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1551,6 +1661,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1580,6 +1691,7 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1611,6 +1723,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1640,6 +1753,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1671,6 +1785,7 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1697,6 +1812,7 @@ void PopupMenu::add_submenu_node_item(const String &p_label, PopupMenu *p_submen
item.text = p_label;
item.xl_text = atr(p_label);
item.id = p_id == -1 ? items.size() : p_id;
item.accessibility_item_dirty = true;
item.submenu = p_submenu;
item.submenu_name = p_submenu->get_name();
items.push_back(item);
@ -1710,6 +1826,7 @@ void PopupMenu::add_submenu_node_item(const String &p_label, PopupMenu *p_submen
}
_shape_item(items.size() - 1);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
@ -1731,15 +1848,18 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
return;
}
items.write[p_idx].text = p_text;
items.write[p_idx].xl_text = atr(p_text);
items.write[p_idx].xl_text = _atr(p_idx, p_text);
items.write[p_idx].dirty = true;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_text(global_menu, p_idx, items[p_idx].xl_text);
}
_shape_item(p_idx);
_shape_item(p_idx);
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@ -1750,9 +1870,14 @@ void PopupMenu::set_item_text_direction(int p_idx, Control::TextDirection p_text
}
ERR_FAIL_INDEX(p_idx, items.size());
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
if (items[p_idx].text_direction != p_text_direction) {
items.write[p_idx].text_direction = p_text_direction;
items.write[p_idx].dirty = true;
items.write[p_idx].accessibility_item_dirty = true;
_shape_item(p_idx);
queue_accessibility_update();
control->queue_redraw();
}
}
@ -1765,10 +1890,28 @@ void PopupMenu::set_item_language(int p_idx, const String &p_language) {
if (items[p_idx].language != p_language) {
items.write[p_idx].language = p_language;
items.write[p_idx].dirty = true;
items.write[p_idx].accessibility_item_dirty = true;
_shape_item(p_idx);
queue_accessibility_update();
control->queue_redraw();
}
}
void PopupMenu::set_item_auto_translate_mode(int p_idx, AutoTranslateMode p_mode) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].auto_translate_mode == p_mode) {
return;
}
items.write[p_idx].auto_translate_mode = p_mode;
items.write[p_idx].xl_text = _atr(p_idx, items[p_idx].text);
items.write[p_idx].dirty = true;
control->queue_redraw();
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
if (p_idx < 0) {
p_idx += get_item_count();
@ -1832,11 +1975,13 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
}
items.write[p_idx].checked = p_checked;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_checked(global_menu, p_idx, p_checked);
}
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
_menu_changed();
@ -1875,11 +2020,13 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
items.write[p_idx].accel = p_accel;
items.write[p_idx].dirty = true;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_accelerator(global_menu, p_idx, p_accel);
}
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
_menu_changed();
@ -1911,11 +2058,13 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
}
items.write[p_idx].disabled = p_disabled;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_disabled(global_menu, p_idx, p_disabled);
}
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
_menu_changed();
@ -1979,11 +2128,13 @@ void PopupMenu::set_item_submenu_node(int p_idx, PopupMenu *p_submenu) {
void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checked = !items[p_idx].checked;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_checked(global_menu, p_idx, items[p_idx].checked);
}
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
_menu_changed();
@ -2009,6 +2160,11 @@ String PopupMenu::get_item_language(int p_idx) const {
return items[p_idx].language;
}
Node::AutoTranslateMode PopupMenu::get_item_auto_translate_mode(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), AUTO_TRANSLATE_MODE_INHERIT);
return items[p_idx].auto_translate_mode;
}
int PopupMenu::get_item_idx_from_text(const String &text) const {
for (int idx = 0; idx < items.size(); idx++) {
if (items[idx].text == text) {
@ -2115,6 +2271,9 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
}
items.write[p_idx].separator = p_separator;
items.write[p_idx].accessibility_item_dirty = true;
queue_accessibility_update();
control->queue_redraw();
}
@ -2135,11 +2294,13 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
}
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_checkable(global_menu, p_idx, p_checkable);
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
@ -2156,11 +2317,13 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
}
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_radio_checkable(global_menu, p_idx, p_radio_checkable);
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
@ -2176,11 +2339,13 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
}
items.write[p_idx].tooltip = p_tooltip;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_tooltip(global_menu, p_idx, p_tooltip);
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
@ -2280,11 +2445,13 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) {
}
items.write[p_idx].state = p_state;
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_state(global_menu, p_idx, p_state);
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
@ -2329,11 +2496,13 @@ 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;
}
items.write[p_idx].accessibility_item_dirty = true;
if (global_menu.is_valid()) {
NativeMenu::get_singleton()->set_item_state(global_menu, p_idx, items[p_idx].state);
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
@ -2367,11 +2536,12 @@ void PopupMenu::set_focused_item(int p_idx) {
return;
}
prev_mouse_over = mouse_over;
mouse_over = p_idx;
if (mouse_over != -1) {
scroll_to_item(mouse_over);
}
queue_accessibility_update();
control->queue_redraw();
}
@ -2393,6 +2563,10 @@ void PopupMenu::set_item_count(int p_count) {
if (is_global && prev_size > p_count) {
for (int i = prev_size - 1; i >= p_count; i--) {
nmenu->remove_item(global_menu, i);
if (items[i].accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(items.write[i].accessibility_item_element);
items.write[i].accessibility_item_element = RID();
}
}
}
@ -2573,6 +2747,10 @@ void PopupMenu::activate_item(int p_idx) {
void PopupMenu::remove_item(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(items.write[p_idx].accessibility_item_element);
items.write[p_idx].accessibility_item_element = RID();
}
if (items[p_idx].shortcut.is_valid()) {
_unref_shortcut(items[p_idx].shortcut);
}
@ -2592,6 +2770,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
Item sep;
sep.separator = true;
sep.id = p_id;
sep.accessibility_item_dirty = true;
if (!p_text.is_empty()) {
sep.text = p_text;
sep.xl_text = atr(p_text);
@ -2607,7 +2786,11 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
}
void PopupMenu::clear(bool p_free_submenus) {
for (const Item &I : items) {
for (Item &I : items) {
if (I.accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(I.accessibility_item_element);
I.accessibility_item_element = RID();
}
if (I.shortcut.is_valid()) {
_unref_shortcut(I.shortcut);
}
@ -2631,7 +2814,9 @@ void PopupMenu::clear(bool p_free_submenus) {
}
items.clear();
prev_mouse_over = -1;
mouse_over = -1;
queue_accessibility_update();
control->queue_redraw();
child_controls_changed();
notify_property_list_changed();
@ -2818,6 +3003,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_text", "index", "text"), &PopupMenu::set_item_text);
ClassDB::bind_method(D_METHOD("set_item_text_direction", "index", "direction"), &PopupMenu::set_item_text_direction);
ClassDB::bind_method(D_METHOD("set_item_language", "index", "language"), &PopupMenu::set_item_language);
ClassDB::bind_method(D_METHOD("set_item_auto_translate_mode", "index", "mode"), &PopupMenu::set_item_auto_translate_mode);
ClassDB::bind_method(D_METHOD("set_item_icon", "index", "icon"), &PopupMenu::set_item_icon);
ClassDB::bind_method(D_METHOD("set_item_icon_max_width", "index", "width"), &PopupMenu::set_item_icon_max_width);
ClassDB::bind_method(D_METHOD("set_item_icon_modulate", "index", "modulate"), &PopupMenu::set_item_icon_modulate);
@ -2844,6 +3030,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_text", "index"), &PopupMenu::get_item_text);
ClassDB::bind_method(D_METHOD("get_item_text_direction", "index"), &PopupMenu::get_item_text_direction);
ClassDB::bind_method(D_METHOD("get_item_language", "index"), &PopupMenu::get_item_language);
ClassDB::bind_method(D_METHOD("get_item_auto_translate_mode", "index"), &PopupMenu::get_item_auto_translate_mode);
ClassDB::bind_method(D_METHOD("get_item_icon", "index"), &PopupMenu::get_item_icon);
ClassDB::bind_method(D_METHOD("get_item_icon_max_width", "index"), &PopupMenu::get_item_icon_max_width);
ClassDB::bind_method(D_METHOD("get_item_icon_modulate", "index"), &PopupMenu::get_item_icon_modulate);
@ -2983,6 +3170,23 @@ void PopupMenu::_native_popup(const Rect2i &p_rect) {
NativeMenu::get_singleton()->popup(global_menu, popup_pos);
}
String PopupMenu::_atr(int p_idx, const String &p_text) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), atr(p_text));
switch (items[p_idx].auto_translate_mode) {
case AUTO_TRANSLATE_MODE_INHERIT: {
return atr(p_text);
} break;
case AUTO_TRANSLATE_MODE_ALWAYS: {
return tr(p_text);
} break;
case AUTO_TRANSLATE_MODE_DISABLED: {
return p_text;
} break;
}
ERR_FAIL_V_MSG(atr(p_text), "Unexpected auto translate mode: " + itos(items[p_idx].auto_translate_mode));
}
void PopupMenu::popup(const Rect2i &p_bounds) {
bool native = global_menu.is_valid();
#ifdef TOOLS_ENABLED
@ -2994,18 +3198,30 @@ void PopupMenu::popup(const Rect2i &p_bounds) {
if (native) {
_native_popup(p_bounds != Rect2i() ? p_bounds : Rect2i(get_position(), Size2i()));
} else {
set_flag(FLAG_NO_FOCUS, !is_embedded());
if (is_inside_tree()) {
bool ac = get_tree()->is_accessibility_enabled();
// Note: Native popup menus need keyboard focus to work with screen reader.
set_flag(FLAG_POPUP, !ac);
set_flag(FLAG_NO_FOCUS, !is_embedded() && !ac);
if (ac) {
set_ac_popup();
}
}
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.
Size2 scale = get_parent_viewport()->get_popup_base_transform().get_scale();
CanvasItem *c = Object::cast_to<CanvasItem>(get_parent());
if (c) {
scale *= c->get_global_transform_with_canvas().get_scale();
}
real_t popup_scale = MIN(scale.x, scale.y);
set_content_scale_factor(popup_scale);
Size2 minsize = get_contents_minimum_size() * popup_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);
}
}
@ -3023,7 +3239,15 @@ void PopupMenu::set_visible(bool p_visible) {
_native_popup(Rect2i(get_position(), get_size()));
}
} else {
set_flag(FLAG_NO_FOCUS, !is_embedded());
if (is_inside_tree()) {
bool ac = get_tree()->is_accessibility_enabled();
// Note: Native popup menus need keyboard focus to work with screen reader.
set_flag(FLAG_POPUP, !ac);
set_flag(FLAG_NO_FOCUS, !is_embedded() && !ac);
if (ac) {
set_ac_popup();
}
}
Popup::set_visible(p_visible);
}