refactor(linux): combine r#type and native_* into sum type

This commit is contained in:
Ngo Iok Ui (Wu Yu Wei) 2022-06-11 20:35:33 +08:00 committed by GitHub
parent 7520e19645
commit 421b00f597
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 77 deletions

View file

@ -323,7 +323,7 @@ impl TextMenuItem {
} }
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
pub enum NativeMenuItem { pub enum NativeMenuItem {
/// A native “About” menu item. /// A native “About” menu item.
/// ///
@ -427,7 +427,7 @@ pub enum NativeMenuItem {
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **macOS**: The metadata is ignored. /// - **macOS**: The metadata is ignored.
#[derive(Debug, Clone, Default)] #[derive(PartialEq, Eq, Debug, Clone, Default)]
pub struct AboutMetadata { pub struct AboutMetadata {
/// The application name. /// The application name.
pub version: Option<String>, pub version: Option<String>,

View file

@ -8,34 +8,25 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
static COUNTER: Counter = Counter::new(); static COUNTER: Counter = Counter::new();
/// Generic shared type describing a menu entry. It can be one of [`MenuEntryType`] /// Generic shared type describing a menu entry. It can be one of [`MenuEntryType`]
#[derive(Debug, Default)] #[derive(Debug)]
struct MenuEntry { struct MenuEntry {
label: String, label: String,
enabled: bool, enabled: bool,
r#type: MenuEntryType, r#type: MenuEntryType,
item_id: Option<u64>, item_id: Option<u64>,
accelerator: Option<String>, accelerator: Option<String>,
native_menu_item: Option<NativeMenuItem>,
// NOTE(amrbashir): because gtk doesn't allow using the same [`gtk::MenuItem`]
// multiple times, and thus can't be used in multiple windows, each entry
// keeps a vector of a [`gtk::MenuItem`] or a tuple of [`gtk::MenuItem`] and [`gtk::Menu`] if its a menu
// and push to it every time [`Menu::init_for_gtk_window`] is called.
native_items: Option<Vec<gtk::MenuItem>>,
native_menus: Option<Vec<(gtk::MenuItem, gtk::Menu)>>,
entries: Option<Vec<Rc<RefCell<MenuEntry>>>>, entries: Option<Vec<Rc<RefCell<MenuEntry>>>>,
} }
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
enum MenuEntryType { enum MenuEntryType {
Submenu, // NOTE(amrbashir): because gtk doesn't allow using the same [`gtk::MenuItem`]
Text, // multiple times, and thus can't be used in multiple windows, each entry
Native, // keeps a vector of a [`gtk::MenuItem`] or a tuple of [`gtk::MenuItem`] and [`gtk::Menu`] if its a menu
} // and push to it every time [`Menu::init_for_gtk_window`] is called.
Submenu(Vec<(gtk::MenuItem, gtk::Menu)>),
impl Default for MenuEntryType { Text(Vec<gtk::MenuItem>),
fn default() -> Self { Native(NativeMenuItem),
MenuEntryType::Text
}
} }
struct InnerMenu { struct InnerMenu {
@ -67,9 +58,9 @@ impl Menu {
label: label.clone(), label: label.clone(),
enabled, enabled,
entries: Some(Vec::new()), entries: Some(Vec::new()),
r#type: MenuEntryType::Submenu, r#type: MenuEntryType::Submenu(Vec::new()),
native_menus: Some(Vec::new()), item_id: Default::default(),
..Default::default() accelerator: None,
})); }));
let mut inner = self.0.borrow_mut(); let mut inner = self.0.borrow_mut();
@ -77,12 +68,10 @@ impl Menu {
if let Some(menu_bar) = menu_bar { if let Some(menu_bar) = menu_bar {
let (item, submenu) = create_gtk_submenu(&label, enabled); let (item, submenu) = create_gtk_submenu(&label, enabled);
menu_bar.append(&item); menu_bar.append(&item);
entry let mut native_menus = entry.borrow_mut();
.borrow_mut() if let MenuEntryType::Submenu(m) = &mut native_menus.r#type {
.native_menus m.push((item, submenu));
.as_mut() }
.unwrap()
.push((item, submenu));
} }
} }
@ -199,9 +188,11 @@ impl Submenu {
pub fn set_label(&mut self, label: impl AsRef<str>) { pub fn set_label(&mut self, label: impl AsRef<str>) {
let label = label.as_ref().to_string(); let label = label.as_ref().to_string();
let mut entry = self.0.borrow_mut(); let mut entry = self.0.borrow_mut();
for (item, _) in entry.native_menus.as_ref().unwrap() { if let MenuEntryType::Submenu(native_menus) = &mut entry.r#type {
for (item, _) in native_menus {
item.set_label(&to_gtk_menemenoic(&label)); item.set_label(&to_gtk_menemenoic(&label));
} }
}
entry.label = label; entry.label = label;
} }
@ -212,10 +203,12 @@ impl Submenu {
pub fn set_enabled(&mut self, enabled: bool) { pub fn set_enabled(&mut self, enabled: bool) {
let mut entry = self.0.borrow_mut(); let mut entry = self.0.borrow_mut();
entry.enabled = true; entry.enabled = true;
for (item, _) in entry.native_menus.as_ref().unwrap() { if let MenuEntryType::Submenu(native_menus) = &mut entry.r#type {
for (item, _) in native_menus {
item.set_sensitive(enabled); item.set_sensitive(enabled);
} }
} }
}
pub fn add_submenu(&mut self, label: impl AsRef<str>, enabled: bool) -> Submenu { pub fn add_submenu(&mut self, label: impl AsRef<str>, enabled: bool) -> Submenu {
let label = label.as_ref().to_string(); let label = label.as_ref().to_string();
@ -224,21 +217,20 @@ impl Submenu {
label: label.clone(), label: label.clone(),
enabled, enabled,
entries: Some(Vec::new()), entries: Some(Vec::new()),
r#type: MenuEntryType::Submenu, r#type: MenuEntryType::Submenu(Vec::new()),
native_menus: Some(Vec::new()), item_id: Default::default(),
..Default::default() accelerator: None,
})); }));
let mut inner = self.0.borrow_mut(); let mut inner = self.0.borrow_mut();
for (_, menu) in inner.native_menus.as_ref().unwrap() { if let MenuEntryType::Submenu(native_menus) = &mut inner.r#type {
for (_, menu) in native_menus {
let (item, submenu) = create_gtk_submenu(&label, enabled); let (item, submenu) = create_gtk_submenu(&label, enabled);
menu.append(&item); menu.append(&item);
entry if let MenuEntryType::Submenu(menus) = &mut entry.borrow_mut().r#type {
.borrow_mut() menus.push((item, submenu));
.native_menus }
.as_mut() }
.unwrap()
.push((item, submenu));
} }
inner.entries.as_mut().unwrap().push(entry.clone()); inner.entries.as_mut().unwrap().push(entry.clone());
@ -257,16 +249,16 @@ impl Submenu {
let entry = Rc::new(RefCell::new(MenuEntry { let entry = Rc::new(RefCell::new(MenuEntry {
label: label.clone(), label: label.clone(),
enabled, enabled,
r#type: MenuEntryType::Text, r#type: MenuEntryType::Text(Vec::new()),
item_id: Some(id), item_id: Some(id),
accelerator: accelerator.map(|s| s.to_string()), accelerator: accelerator.map(|s| s.to_string()),
native_items: Some(Vec::new()), entries: None,
..Default::default()
})); }));
let mut inner = self.0.borrow_mut(); let mut inner = self.0.borrow_mut();
for (_, menu) in inner.native_menus.as_ref().unwrap() { if let MenuEntryType::Submenu(native_menus) = &mut inner.r#type {
for (_, menu) in native_menus {
let item = create_gtk_text_menu_item( let item = create_gtk_text_menu_item(
&label, &label,
enabled, enabled,
@ -275,7 +267,10 @@ impl Submenu {
&*self.1, &*self.1,
); );
menu.append(&item); menu.append(&item);
entry.borrow_mut().native_items.as_mut().unwrap().push(item); if let MenuEntryType::Text(native_items) = &mut entry.borrow_mut().r#type {
native_items.push(item);
}
}
} }
inner.entries.as_mut().unwrap().push(entry.clone()); inner.entries.as_mut().unwrap().push(entry.clone());
@ -285,14 +280,19 @@ impl Submenu {
pub fn add_native_item(&mut self, item: NativeMenuItem) { pub fn add_native_item(&mut self, item: NativeMenuItem) {
let mut inner = self.0.borrow_mut(); let mut inner = self.0.borrow_mut();
for (_, menu) in inner.native_menus.as_ref().unwrap() { if let MenuEntryType::Submenu(native_menus) = &mut inner.r#type {
for (_, menu) in native_menus {
item.add_to_gtk_menu(menu); item.add_to_gtk_menu(menu);
} }
}
let entry = Rc::new(RefCell::new(MenuEntry { let entry = Rc::new(RefCell::new(MenuEntry {
r#type: MenuEntryType::Native, r#type: MenuEntryType::Native(item),
native_menu_item: Some(item), label: Default::default(),
..Default::default() enabled: Default::default(),
item_id: Default::default(),
accelerator: Default::default(),
entries: Default::default(),
})); }));
inner.entries.as_mut().unwrap().push(entry); inner.entries.as_mut().unwrap().push(entry);
} }
@ -309,9 +309,11 @@ impl TextMenuItem {
pub fn set_label(&mut self, label: impl AsRef<str>) { pub fn set_label(&mut self, label: impl AsRef<str>) {
let label = label.as_ref().to_string(); let label = label.as_ref().to_string();
let mut entry = self.0.borrow_mut(); let mut entry = self.0.borrow_mut();
for item in entry.native_items.as_ref().unwrap() { if let MenuEntryType::Text(native_items) = &mut entry.r#type {
for item in native_items {
item.set_label(&to_gtk_menemenoic(&label)); item.set_label(&to_gtk_menemenoic(&label));
} }
}
entry.label = label; entry.label = label;
} }
@ -321,9 +323,11 @@ impl TextMenuItem {
pub fn set_enabled(&mut self, enabled: bool) { pub fn set_enabled(&mut self, enabled: bool) {
let mut entry = self.0.borrow_mut(); let mut entry = self.0.borrow_mut();
for item in entry.native_items.as_ref().unwrap() { if let MenuEntryType::Text(native_items) = &mut entry.r#type {
for item in native_items {
item.set_sensitive(enabled); item.set_sensitive(enabled);
} }
}
entry.enabled = enabled; entry.enabled = enabled;
} }
@ -339,14 +343,14 @@ fn add_entries_to_menu<M: IsA<gtk::MenuShell>>(
) { ) {
for entry in entries { for entry in entries {
let mut entry = entry.borrow_mut(); let mut entry = entry.borrow_mut();
match entry.r#type { let (item, submenu) = match &entry.r#type {
MenuEntryType::Submenu => { MenuEntryType::Submenu(_) => {
let (item, submenu) = create_gtk_submenu(&entry.label, entry.enabled); let (item, submenu) = create_gtk_submenu(&entry.label, entry.enabled);
gtk_menu.append(&item); gtk_menu.append(&item);
add_entries_to_menu(&submenu, entry.entries.as_ref().unwrap(), accel_group); add_entries_to_menu(&submenu, entry.entries.as_ref().unwrap(), accel_group);
entry.native_menus.as_mut().unwrap().push((item, submenu)); (Some(item), Some(submenu))
} }
MenuEntryType::Text => { MenuEntryType::Text(_) => {
let item = create_gtk_text_menu_item( let item = create_gtk_text_menu_item(
&entry.label, &entry.label,
entry.enabled, entry.enabled,
@ -355,14 +359,23 @@ fn add_entries_to_menu<M: IsA<gtk::MenuShell>>(
accel_group, accel_group,
); );
gtk_menu.append(&item); gtk_menu.append(&item);
entry.native_items.as_mut().unwrap().push(item); (Some(item), None)
} }
MenuEntryType::Native => entry MenuEntryType::Native(native_menu_item) => {
.native_menu_item native_menu_item.add_to_gtk_menu(gtk_menu);
.as_ref() (None, None)
.unwrap()
.add_to_gtk_menu(gtk_menu),
} }
};
match &mut entry.r#type {
MenuEntryType::Submenu(native_menus) => {
native_menus.push((item.unwrap(), submenu.unwrap()));
}
MenuEntryType::Text(native_items) => {
native_items.push(item.unwrap());
}
MenuEntryType::Native(_) => {}
};
} }
} }