use crate::input::UiEvent;
use crate::key::Key;
use crate::menu::{MenuBar, MenuItem};
use crate::runtime::Core;
use crate::tree::OriginId;
impl Core {
pub fn declare_menu_bar(&mut self, bar: MenuBar) {
let bar = normalize(bar);
if self.menu_bar.as_ref() == Some(&bar) {
return;
}
let open_moved = self.menu_bar_open.is_some_and(|i| {
fn label(b: &MenuBar, i: usize) -> Option<&str> {
b.menus.get(i).map(|m| m.label.as_str())
}
self.menu_bar.as_ref().and_then(|old| label(old, i)) != label(&bar, i)
});
if open_moved {
self.menu_bar_open = None;
self.menu_bar_sub = super::menu_api::Submenus::default();
}
self.menu_bar = Some(bar);
self.menu_bar_origin = self.origin();
self.menu_bar_rev += 1;
}
pub fn menu_bar(&self) -> Option<&MenuBar> {
self.menu_bar.as_ref()
}
pub fn menu_bar_revision(&self) -> u64 {
self.menu_bar_rev
}
pub fn set_native_menu_bar(&mut self, on: bool) {
self.native_menu_bar = on;
}
pub fn native_menu_bar(&self) -> bool {
self.native_menu_bar
}
pub fn menu_bar_open(&self) -> Option<usize> {
self.menu_bar_open
}
pub fn menu_bar_submenus(&self) -> &[usize] {
&self.menu_bar_sub.open
}
pub fn set_menu_bar_open(&mut self, menu: Option<usize>) {
let menu = menu.filter(|i| {
self.menu_bar
.as_ref()
.and_then(|b| b.menus.get(*i))
.is_some_and(|m| m.enabled && !m.items.is_empty())
});
if menu == self.menu_bar_open {
return;
}
self.menu_bar_sub = super::menu_api::Submenus::default();
if menu.is_some()
&& let Some(editor) = self.edit.focused()
{
self.menu_editor = Some(editor);
}
self.menu_bar_open = menu;
}
pub fn activate_menu_bar_item(&mut self, menu: usize, item: usize) -> Vec<UiEvent> {
self.activate_menu_bar_path(menu, &[item])
}
pub fn activate_menu_bar_path(&mut self, menu: usize, path: &[usize]) -> Vec<UiEvent> {
let mut out = Vec::new();
let Some(item) = self
.menu_bar
.as_ref()
.and_then(|b| b.menus.get(menu))
.filter(|m| m.enabled && MenuItem::choosable_at(&m.items, path))
.and_then(|m| MenuItem::at_path(&m.items, path))
.cloned()
else {
return out;
};
self.menu_editor = self.edit.focused();
let (target, origin) = (self.menu_bar_target(), self.menu_bar_origin);
self.perform_menu_item(&item, target, origin, &mut out);
out
}
fn menu_bar_target(&self) -> Key {
self.menu_bar_root.unwrap_or(Key::ROOT)
}
pub(crate) fn set_menu_bar_root(&mut self, root: Key) {
self.menu_bar_root = Some(root);
}
pub(crate) fn consume_menu_bar_events(&mut self, out: &mut Vec<UiEvent>) {
if self.menu_bar_root.is_none() {
return;
}
let taken = Self::take_surface_events(out, OriginId::MENU_BAR);
let (title, row, dismissed) = (taken.title, taken.row_path(), taken.dismissed);
if let Some(i) = title {
let next = (self.menu_bar_open != Some(i)).then_some(i);
self.set_menu_bar_open(next);
} else if let Some(path) = row {
let Some(menu) = self.menu_bar_open else {
return;
};
let item = self
.menu_bar
.as_ref()
.and_then(|b| b.item_at(menu, &path))
.cloned();
if item.as_ref().is_some_and(MenuItem::has_submenu) {
let keyboard = self.focus_visible;
self.open_submenu(super::MenuSurface::Bar, path, keyboard);
return;
}
self.set_menu_bar_open(None);
if let Some(item) = item {
let (target, origin) = (self.menu_bar_target(), self.menu_bar_origin);
self.perform_menu_item(&item, target, origin, out);
}
} else if dismissed {
self.set_menu_bar_open(None);
}
}
pub(crate) fn note_menu_bar_editor(&mut self) {
self.menu_editor = self.edit.focused();
}
}
fn normalize(mut bar: MenuBar) -> MenuBar {
for menu in &mut bar.menus {
MenuItem::normalize_accels(&mut menu.items);
}
bar
}