Skip to content

Commit f00b6f8

Browse files
committed
correctly deselect nested menu items of orphaned menus
1 parent 74ac365 commit f00b6f8

1 file changed

Lines changed: 32 additions & 39 deletions

File tree

fyrox-ui/src/menu.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl Control for Menu {
269269
}
270270
} else if let Some(WidgetMessage::KeyDown(key_code)) = message.data() {
271271
if !message.handled() {
272-
if keyboard_navigation(ui, *key_code, self, self.handle) {
272+
if keyboard_navigation(ui, *key_code, self, self.handle.to_variant()) {
273273
message.set_handled(true);
274274
} else if *key_code == KeyCode::Escape {
275275
ui.send(self.handle, MenuMessage::Deactivate);
@@ -463,6 +463,27 @@ impl MenuItem {
463463
WidgetMessage::Visibility(!self.items_container.is_empty()),
464464
);
465465
}
466+
467+
fn close_menu_chain(&self, ui: &UserInterface) {
468+
let mut menu_item_ref_container = Some(self);
469+
while let Some(menu_item_ref) = menu_item_ref_container {
470+
let popup_handle =
471+
menu_item_ref.find_by_criteria_up(ui, |n| n.has_component::<ContextMenu>());
472+
473+
ui.send(
474+
menu_item_ref.handle,
475+
MenuItemMessage::Close { deselect: true },
476+
);
477+
478+
if let Ok(panel) = ui.try_get_of_type::<ContextMenu>(popup_handle) {
479+
// Continue search from parent menu item of popup.
480+
menu_item_ref_container = ui.try_get(panel.parent_menu_item).ok();
481+
} else {
482+
// Prevent infinite loops.
483+
break;
484+
}
485+
}
486+
}
466487
}
467488

468489
// MenuItem uses popup to show its content, popup can be top-most only if it is
@@ -475,7 +496,7 @@ fn find_menu(from: Handle<UiNode>, ui: &UserInterface) -> Handle<UiNode> {
475496
while handle.is_some() {
476497
if let Some((_, panel)) = ui.find_component_up::<ContextMenu>(handle) {
477498
// Continue search from parent menu item of popup.
478-
handle = panel.parent_menu_item;
499+
handle = panel.parent_menu_item.to_base();
479500
} else {
480501
// Maybe we have Menu as parent for MenuItem.
481502
return ui.find_handle_up(handle, &mut |n| n.cast::<Menu>().is_some());
@@ -500,25 +521,6 @@ fn is_any_menu_item_contains_point(ui: &UserInterface, pt: Vector2<f32>) -> bool
500521
false
501522
}
502523

503-
fn close_menu_chain(from: Handle<UiNode>, ui: &UserInterface) {
504-
let mut handle = from;
505-
while handle.is_some() {
506-
let popup_handle = ui.find_handle_up(handle, &mut |n| n.has_component::<ContextMenu>());
507-
508-
if let Ok(panel) = ui.try_get_of_type::<ContextMenu>(popup_handle) {
509-
if *panel.popup.is_open {
510-
ui.send(popup_handle, PopupMessage::Close);
511-
}
512-
513-
// Continue search from parent menu item of popup.
514-
handle = panel.parent_menu_item;
515-
} else {
516-
// Prevent infinite loops.
517-
break;
518-
}
519-
}
520-
}
521-
522524
uuid_provider!(MenuItem = "72e002c6-6060-4583-b5b7-0c5500244fef");
523525

524526
impl Control for MenuItem {
@@ -564,7 +566,7 @@ impl Control for MenuItem {
564566
ui.send(menu, MenuMessage::Deactivate);
565567
} else {
566568
// Or close the menu chain if menu item is in "orphaned" state.
567-
close_menu_chain(self.parent(), ui);
569+
self.close_menu_chain(ui);
568570
}
569571
}
570572
message.set_handled(true);
@@ -722,7 +724,7 @@ impl Control for MenuItem {
722724
if let Some(panel) = node.component_ref::<ContextMenu>() {
723725
// Once we found popup in chain, we must extract handle
724726
// of parent menu item to continue search.
725-
handle = panel.parent_menu_item;
727+
handle = panel.parent_menu_item.to_base();
726728
} else {
727729
handle = node.parent();
728730
}
@@ -756,12 +758,8 @@ impl Control for MenuItem {
756758
if !is_any_menu_item_contains_point(ui, ui.cursor_position())
757759
&& find_menu(self.parent(), ui).is_none()
758760
{
759-
if *panel.popup.is_open {
760-
ui.send(*self.items_panel, PopupMessage::Close);
761-
}
762-
763761
// Close all other popups.
764-
close_menu_chain(self.parent(), ui);
762+
self.close_menu_chain(ui);
765763
}
766764
}
767765
}
@@ -1138,7 +1136,7 @@ pub struct ContextMenu {
11381136
#[component(include)]
11391137
pub popup: Popup,
11401138
/// Parent menu item of the context menu. Allows you to build chained context menus.
1141-
pub parent_menu_item: Handle<UiNode>,
1139+
pub parent_menu_item: Handle<MenuItem>,
11421140
}
11431141

11441142
impl ConstructorProvider<UiNode, UserInterface> for ContextMenu {
@@ -1179,13 +1177,8 @@ impl Control for ContextMenu {
11791177

11801178
if let Some(WidgetMessage::KeyDown(key_code)) = message.data() {
11811179
if !message.handled() {
1182-
if let Ok(parent_menu_item) = ui.try_get_node(self.parent_menu_item) {
1183-
if keyboard_navigation(
1184-
ui,
1185-
*key_code,
1186-
parent_menu_item.deref(),
1187-
self.parent_menu_item,
1188-
) {
1180+
if let Ok(parent_menu_item) = ui.try_get(self.parent_menu_item) {
1181+
if keyboard_navigation(ui, *key_code, parent_menu_item, self.parent_menu_item) {
11891182
message.set_handled(true);
11901183
}
11911184
}
@@ -1197,7 +1190,7 @@ impl Control for ContextMenu {
11971190
/// Creates [`ContextMenu`] widgets.
11981191
pub struct ContextMenuBuilder {
11991192
popup_builder: PopupBuilder,
1200-
parent_menu_item: Handle<UiNode>,
1193+
parent_menu_item: Handle<MenuItem>,
12011194
}
12021195

12031196
impl ContextMenuBuilder {
@@ -1210,7 +1203,7 @@ impl ContextMenuBuilder {
12101203
}
12111204

12121205
/// Sets the desired parent menu item.
1213-
pub fn with_parent_menu_item(mut self, parent_menu_item: Handle<UiNode>) -> Self {
1206+
pub fn with_parent_menu_item(mut self, parent_menu_item: Handle<MenuItem>) -> Self {
12141207
self.parent_menu_item = parent_menu_item;
12151208
self
12161209
}
@@ -1234,7 +1227,7 @@ fn keyboard_navigation(
12341227
ui: &UserInterface,
12351228
key_code: KeyCode,
12361229
parent_menu_item: &dyn Control,
1237-
parent_menu_item_handle: Handle<UiNode>,
1230+
parent_menu_item_handle: Handle<MenuItem>,
12381231
) -> bool {
12391232
let Some(items_container) = parent_menu_item
12401233
.query_component_ref(TypeId::of::<ItemsContainer>())

0 commit comments

Comments
 (0)