From 91e3d3e05ad46a9da7078a212dec5f9bb1252ab1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 30 Oct 2023 10:19:52 -0600 Subject: [PATCH] Add key shortcut support, use key bindings to determine menu text --- src/config.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 41 +++++++++++++++++++----------- src/menu.rs | 25 +++++++++++++++---- 3 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 src/config.rs diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..5d3db0d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,69 @@ +use cosmic::iced::keyboard::{KeyCode, Modifiers}; +use std::{collections::HashMap, fmt}; + +use crate::{fl, Message}; + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct KeyBind { + pub modifiers: Modifiers, + pub key_code: KeyCode, +} + +impl KeyBind { + //TODO: load from config + pub fn load() -> HashMap { + let mut keybinds = HashMap::new(); + + macro_rules! bind { + ($modifiers:ident, $key_code:ident, $message:ident) => {{ + keybinds.insert( + KeyBind { + modifiers: Modifiers::$modifiers, + key_code: KeyCode::$key_code, + }, + Message::$message, + ); + }}; + } + + bind!(CTRL, N, New); + bind!(CTRL, O, OpenFileDialog); + bind!(CTRL, S, Save); + + keybinds + } +} + +impl fmt::Display for KeyBind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.modifiers.logo() { + write!(f, "Super + ")?; + } + if self.modifiers.control() { + write!(f, "Ctrl + ")?; + } + if self.modifiers.alt() { + write!(f, "Alt + ")?; + } + if self.modifiers.shift() { + write!(f, "Shift + ")?; + } + write!(f, "{:?}", self.key_code) + } +} + +#[derive(Clone, Debug)] +pub struct Config { + pub wrap: bool, + pub keybinds: HashMap, +} + +impl Config { + //TODO: load from cosmic-config + pub fn load() -> Self { + Self { + wrap: false, + keybinds: KeyBind::load(), + } + } +} diff --git a/src/main.rs b/src/main.rs index baa4f92..f8b9351 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use cosmic::{ app::{message, Command, Core, Settings}, executor, iced::{ + event, keyboard, subscription, widget::{row, text}, Alignment, Length, Limits, }, @@ -18,6 +19,9 @@ use std::{ sync::Mutex, }; +use config::{Config, KeyBind}; +mod config; + mod localize; use self::menu::menu_bar; @@ -50,18 +54,6 @@ fn main() -> Result<(), Box> { Ok(()) } -#[derive(Clone, Debug)] -pub struct Config { - wrap: bool, -} - -impl Config { - //TODO: load from cosmic-config - pub fn new() -> Self { - Self { wrap: false } - } -} - pub struct App { core: Core, nav_model: segmented_button::SingleSelectModel, @@ -70,8 +62,9 @@ pub struct App { } #[allow(dead_code)] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum Message { + KeyBind(KeyBind), New, OpenFileDialog, OpenFile(PathBuf), @@ -289,7 +282,7 @@ impl cosmic::Application for App { core, nav_model: nav_bar::Model::builder().build(), tab_model: segmented_button::Model::builder().build(), - config: Config::new(), + config: Config::load(), }; for arg in env::args().skip(1) { @@ -383,6 +376,13 @@ impl cosmic::Application for App { fn update(&mut self, message: Message) -> Command { match message { + Message::KeyBind(key_bind) => { + for (config_key_bind, config_message) in self.config.keybinds.iter() { + if config_key_bind == &key_bind { + return self.update(config_message.clone()); + } + } + } Message::New => { self.open_tab(None); return self.update_title(); @@ -541,4 +541,17 @@ impl cosmic::Application for App { //content.explain(cosmic::iced::Color::WHITE) content } + + fn subscription(&self) -> subscription::Subscription { + subscription::events_with(|event, status| match event { + event::Event::Keyboard(keyboard::Event::KeyPressed { + modifiers, + key_code, + }) => Some(Message::KeyBind(KeyBind { + modifiers, + key_code, + })), + _ => None, + }) + } } diff --git a/src/menu.rs b/src/menu.rs index 4a3f17e..d21b60c 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -39,8 +39,23 @@ pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { let menu_folder = |label| menu_button!(widget::text(label), horizontal_space(Length::Fill), ">"); - let menu_item = - |label, message| MenuTree::new(menu_button!(widget::text(label)).on_press(message)); + let menu_item = |label, message| { + let mut key = String::new(); + for (config_key_bind, config_message) in config.keybinds.iter() { + if config_message == &message { + key = config_key_bind.to_string(); + break; + } + } + MenuTree::new( + menu_button!( + widget::text(label), + horizontal_space(Length::Fill), + widget::text(key) + ) + .on_press(message), + ) + }; let menu_key = |label, key, message| { MenuTree::new( @@ -53,16 +68,16 @@ pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { MenuTree::with_children( menu_root(fl!("file")), vec![ - menu_key(fl!("new-file"), "Ctrl + N", Message::New), + menu_item(fl!("new-file"), Message::New), menu_key(fl!("new-window"), "Ctrl + Shift + N", Message::Todo), MenuTree::new(horizontal_rule(1)), - menu_key(fl!("open-file"), "Ctrl + O", Message::OpenFileDialog), + menu_item(fl!("open-file"), Message::OpenFileDialog), MenuTree::with_children( menu_folder(fl!("open-recent")), vec![menu_item(fl!("todo"), Message::Todo)], ), MenuTree::new(horizontal_rule(1)), - menu_key(fl!("save"), "Ctrl + S", Message::Save), + menu_item(fl!("save"), Message::Save), menu_key(fl!("save-as"), "Ctrl + Shift + S", Message::Todo), MenuTree::new(horizontal_rule(1)), menu_item(fl!("revert-all-changes"), Message::Todo),