use crate::command::Command;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MenuItem {
Action(ActionItem),
Separator(SeparatorItem),
SubMenu(SubMenuItem),
}
impl MenuItem {
pub fn text(&self) -> Option<&str> {
match self {
Self::Action(action) => Some(&action.label),
Self::SubMenu(submenu) => Some(&submenu.label),
Self::Separator(_) => None,
}
}
pub fn is_enabled(&self) -> bool {
match self {
Self::Action(action) => action.enabled,
Self::SubMenu(submenu) => submenu.enabled,
Self::Separator(_) => false, }
}
pub fn label(&self) -> Option<&str> {
match self {
Self::Action(action) => Some(&action.label),
Self::SubMenu(submenu) => Some(&submenu.label),
Self::Separator(_) => None,
}
}
pub fn hotkey(&self) -> Option<char> {
match self {
Self::Action(action) => action.hotkey,
Self::SubMenu(submenu) => submenu.hotkey,
Self::Separator(_) => None,
}
}
pub fn is_selectable(&self) -> bool {
!matches!(self, Self::Separator(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActionItem {
pub label: String,
pub command: Command,
pub enabled: bool,
pub hotkey: Option<char>,
pub shortcut: Option<String>,
pub help_context: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SeparatorItem;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SubMenuItem {
pub label: String,
pub items: Vec<MenuItem>,
pub enabled: bool,
pub hotkey: Option<char>,
pub help_context: Option<String>,
pub focused_item: Option<usize>,
pub is_open: bool,
}
impl Default for SeparatorItem {
fn default() -> Self {
Self::new()
}
}
impl SeparatorItem {
pub fn new() -> Self {
Self
}
}
impl MenuItem {
pub fn new_action<S: Into<String>, C: Into<Command>>(label: S, command: C) -> Self {
Self::Action(ActionItem::new(label, command))
}
pub fn action_with_hotkey<S: Into<String>, C: Into<Command>>(
label: S,
command: C,
hotkey: char,
) -> Self {
Self::Action(ActionItem::with_hotkey(label, command, hotkey))
}
pub fn action_with_all<S: Into<String>, C: Into<Command>>(
label: S,
command: C,
hotkey: Option<char>,
shortcut: Option<S>,
) -> Self {
Self::Action(ActionItem::with_all(label, command, hotkey, shortcut))
}
pub fn separator() -> Self {
Self::Separator(SeparatorItem::new())
}
pub fn new_submenu<S: Into<String>>(label: S) -> Self {
Self::SubMenu(SubMenuItem::new(label))
}
pub fn submenu_with_hotkey<S: Into<String>>(label: S, hotkey: char) -> Self {
Self::SubMenu(SubMenuItem::with_hotkey(label, hotkey))
}
pub fn submenu_with_items<S: Into<String>>(
label: S,
hotkey: Option<char>,
items: Vec<MenuItem>,
) -> Self {
Self::SubMenu(SubMenuItem::with_items(label, hotkey, items))
}
pub fn action<S: Into<String>, C: Into<Command>>(text: S, command: C) -> Self {
Self::new_action(text, command)
}
pub fn submenu<S: Into<String>>(text: S, items: Vec<MenuItem>) -> Self {
Self::SubMenu(SubMenuItem::with_items(text, None, items))
}
pub fn with_hotkey(mut self, hotkey: char) -> Self {
match &mut self {
Self::Action(action) => action.hotkey = Some(hotkey),
Self::SubMenu(submenu) => submenu.hotkey = Some(hotkey),
Self::Separator(_) => {} }
self
}
pub fn with_shortcut<S: Into<String>>(mut self, shortcut: S) -> Self {
if let Self::Action(action) = &mut self {
action.shortcut = Some(shortcut.into());
}
self
}
pub fn with_help_context<S: Into<String>>(mut self, help_context: S) -> Self {
match &mut self {
Self::Action(action) => action.help_context = Some(help_context.into()),
Self::SubMenu(submenu) => submenu.help_context = Some(help_context.into()),
Self::Separator(_) => {} }
self
}
pub fn with_enabled(mut self, enabled: bool) -> Self {
match &mut self {
Self::Action(action) => action.enabled = enabled,
Self::SubMenu(submenu) => submenu.enabled = enabled,
Self::Separator(_) => {} }
self
}
}
impl ActionItem {
pub fn new<S: Into<String>, C: Into<Command>>(label: S, command: C) -> Self {
Self {
label: label.into(),
command: command.into(),
enabled: true,
hotkey: None,
shortcut: None,
help_context: None,
}
}
pub fn with_hotkey<S: Into<String>, C: Into<Command>>(
label: S,
command: C,
hotkey: char,
) -> Self {
Self {
label: label.into(),
command: command.into(),
enabled: true,
hotkey: Some(hotkey),
shortcut: None,
help_context: None,
}
}
pub fn with_all<S: Into<String>, C: Into<Command>>(
label: S,
command: C,
hotkey: Option<char>,
shortcut: Option<S>,
) -> Self {
Self {
label: label.into(),
command: command.into(),
enabled: true,
hotkey,
shortcut: shortcut.map(|s| s.into()),
help_context: None,
}
}
pub fn hotkey(mut self, hotkey: char) -> Self {
self.hotkey = Some(hotkey);
self
}
pub fn shortcut<S: Into<String>>(mut self, shortcut: S) -> Self {
self.shortcut = Some(shortcut.into());
self
}
pub fn help_context<S: Into<String>>(mut self, help_context: S) -> Self {
self.help_context = Some(help_context.into());
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
}
impl SubMenuItem {
pub fn new<S: Into<String>>(label: S) -> Self {
Self {
label: label.into(),
items: Vec::new(),
enabled: true,
hotkey: None,
help_context: None,
focused_item: None,
is_open: false,
}
}
pub fn with_hotkey<S: Into<String>>(label: S, hotkey: char) -> Self {
Self {
label: label.into(),
items: Vec::new(),
enabled: true,
hotkey: Some(hotkey),
help_context: None,
focused_item: None,
is_open: false,
}
}
pub fn with_items<S: Into<String>>(
label: S,
hotkey: Option<char>,
items: Vec<MenuItem>,
) -> Self {
Self {
label: label.into(),
items,
enabled: true,
hotkey,
help_context: None,
focused_item: None,
is_open: false,
}
}
pub fn hotkey(mut self, hotkey: char) -> Self {
self.hotkey = Some(hotkey);
self
}
pub fn item(mut self, item: MenuItem) -> Self {
self.items.push(item);
self
}
pub fn help_context<S: Into<String>>(mut self, help_context: S) -> Self {
self.help_context = Some(help_context.into());
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
pub fn add_item(&mut self, item: MenuItem) {
self.items.push(item);
}
}