diff --git a/i18n/en/cosmic_term.ftl b/i18n/en/cosmic_term.ftl index 0eda393..4342436 100644 --- a/i18n/en/cosmic_term.ftl +++ b/i18n/en/cosmic_term.ftl @@ -63,33 +63,33 @@ show-headerbar = Show header show-header-description = Reveal the header from the right-click menu. ### Keyboard shortcuts -type-to-search = Type to search... -keyboard-shortcuts = Keyboard shortcuts -menu-keyboard-shortcuts = Keyboard shortcuts... -customize-shortcuts = Customize shortcuts -shortcut-capture-hint = Press new shortcut, or Esc to cancel +add-another-keybinding = Add another keybinding cancel = Cancel -replace = Replace -shortcut-replace-title = Replace shortcut? -shortcut-replace-body = { $binding } is already assigned to { $existing }. Replace it with { $new_action }? -no-shortcuts = No shortcuts -add-shortcut = + Add -shortcut-group-clipboard = Clipboard -shortcut-group-tabs = Tabs -shortcut-group-window = Window -shortcut-group-zoom = Zoom -shortcut-group-other = Other -unbind = Unbind +close-window = Close window copy-or-sigint = Copy or SIGINT -paste-primary = Paste primary +focus-pane-down = Focus pane down focus-pane-left = Focus pane left focus-pane-right = Focus pane right focus-pane-up = Focus pane up -focus-pane-down = Focus pane down -toggle-fullscreen = Toggle fullscreen -close-window = Close window +keyboard-shortcuts = Keyboard shortcuts +menu-keyboard-shortcuts = Keyboard shortcuts... +no-shortcuts = No shortcuts password-manager = Password manager +paste-primary = Paste primary +replace = Replace +reset-to-default = Reset to default +shortcut-capture-hint = Press new shortcut, or Esc to cancel +shortcut-group-clipboard = Clipboard +shortcut-group-other = Other +shortcut-group-tabs = Tabs +shortcut-group-window = Window +shortcut-group-zoom = Zoom +shortcut-replace-body = { $binding } is already assigned to { $existing }. Replace it with { $new_action }? +shortcut-replace-title = Replace shortcut? tab-activate = Activate tab { $number } +toggle-fullscreen = Toggle fullscreen +type-to-search = Type to search... +unbind = Unbind # Find find-placeholder = Find... diff --git a/res/icons/edit-undo-symbolic.svg b/res/icons/edit-undo-symbolic.svg new file mode 100644 index 0000000..7400969 --- /dev/null +++ b/res/icons/edit-undo-symbolic.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/icon_cache.rs b/src/icon_cache.rs index 59c9e0b..21a7dc9 100644 --- a/src/icon_cache.rs +++ b/src/icon_cache.rs @@ -33,6 +33,7 @@ impl IconCache { bundle!("dialog-error-symbolic", 16); bundle!("edit-clear-symbolic", 16); bundle!("edit-delete-symbolic", 16); + bundle!("edit-undo-symbolic", 16); bundle!("list-add-symbolic", 16); bundle!("go-down-symbolic", 16); bundle!("go-up-symbolic", 16); diff --git a/src/main.rs b/src/main.rs index 79b21ff..3ca2723 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,10 +163,7 @@ fn main() -> Result<(), Box> { } }; - let shortcuts_config = shortcuts::ShortcutsConfig { - defaults: shortcuts::Shortcuts::default(), - custom: config.shortcuts_custom.clone(), - }; + let shortcuts_config = shortcuts::ShortcutsConfig::new(config.shortcuts_custom.clone()); let startup_options = if let Some(shell_program) = shell_program_opt { let options = tty::Options { @@ -382,6 +379,7 @@ pub enum Message { ShortcutConflictCancel, ShortcutConflictReplace, ShortcutRemove(shortcuts::Binding, shortcuts::BindingSource), + ShortcutReset(shortcuts::KeyBindAction), ShortcutSearch(String), MouseEnter(pane_grid::Pane), Opacity(u8), @@ -1003,16 +1001,28 @@ impl App { } found_actions = true; - let bindings = self.shortcuts_config.bindings_for_action(action); + let (bindings, changed) = self.shortcuts_config.bindings_for_action(action); + + let mut buttons = widget::row::with_capacity(2); + if changed { + buttons = buttons.push(widget::tooltip( + widget::button::custom(icon_cache_get("edit-undo-symbolic", 16)) + .class(style::Button::Icon) + .on_press(Message::ShortcutReset(action)), + widget::text::body(fl!("reset-to-default")), + widget::tooltip::Position::Top, + )); + } + buttons = buttons.push(widget::tooltip( + widget::button::custom(icon_cache_get("list-add-symbolic", 16)) + .class(style::Button::Icon) + .on_press(Message::ShortcutCaptureStart(action)), + widget::text::body(fl!("add-another-keybinding")), + widget::tooltip::Position::Top, + )); list = list.list_item_padding(pad_m); - list = list.add( - widget::settings::item::builder(action_label).control( - widget::button::custom(icon_cache_get("list-add-symbolic", 16)) - .class(style::Button::Icon) - .on_press(Message::ShortcutCaptureStart(action)), - ), - ); + list = list.add(widget::settings::item::builder(action_label).control(buttons)); list = list.divider_padding(div_m); if bindings.is_empty() { @@ -2090,10 +2100,8 @@ impl Application for App { //TODO: update syntax theme by clearing tabs, only if needed self.config = config; if shortcuts_changed { - self.shortcuts_config = shortcuts::ShortcutsConfig { - defaults: shortcuts::Shortcuts::default(), - custom: self.config.shortcuts_custom.clone(), - }; + self.shortcuts_config = + shortcuts::ShortcutsConfig::new(self.config.shortcuts_custom.clone()); self.key_binds = key_binds(&self.shortcuts_config); } return self.update_config(); @@ -2431,6 +2439,10 @@ impl Application for App { } self.save_shortcuts_custom(); } + Message::ShortcutReset(reset_action) => { + self.shortcuts_config.reset_action(reset_action); + self.save_shortcuts_custom(); + } Message::ShortcutSearch(search) => { self.shortcut_search_focus.set(true); self.shortcut_search_regex = None; diff --git a/src/shortcuts.rs b/src/shortcuts.rs index e5bbd5f..b9b0d4a 100644 --- a/src/shortcuts.rs +++ b/src/shortcuts.rs @@ -163,38 +163,47 @@ pub struct ResolvedBinding { pub source: BindingSource, } -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ShortcutsConfig { - pub defaults: Shortcuts, + defaults: Shortcuts, pub custom: Shortcuts, } impl ShortcutsConfig { + pub fn new(custom: Shortcuts) -> Self { + Self { + defaults: fallback_shortcuts(), + custom, + } + } + pub fn key_binds(&self) -> HashMap { let mut binds = HashMap::new(); - let defaults = self.defaults_or_fallback(); - insert_shortcuts(&defaults, &mut binds, false); + insert_shortcuts(&self.defaults, &mut binds, false); insert_shortcuts(&self.custom, &mut binds, true); binds } - pub fn bindings_for_action(&self, action: KeyBindAction) -> Vec { + pub fn bindings_for_action(&self, action: KeyBindAction) -> (Vec, bool) { let mut bindings = Vec::new(); - let defaults = self.defaults_or_fallback(); - for (binding, default_action) in &defaults.0 { + let mut changed = false; + for (binding, default_action) in &self.defaults.0 { if *default_action != action { continue; } match self.custom.0.get(binding) { - Some(KeyBindAction::Unbind) => (), + Some(KeyBindAction::Unbind) => { + changed = true; + } Some(custom_action) => { if *custom_action == action { bindings.push(ResolvedBinding { binding: binding.clone(), source: BindingSource::Custom, }); + changed = true; } } None => bindings.push(ResolvedBinding { @@ -212,10 +221,11 @@ impl ShortcutsConfig { binding: binding.clone(), source: BindingSource::Custom, }); + changed = true; } } - bindings + (bindings, changed) } pub fn action_for_binding(&self, binding: &Binding) -> Option { @@ -226,16 +236,23 @@ impl ShortcutsConfig { return Some(*action); } - let defaults = self.defaults_or_fallback(); - defaults.0.get(binding).copied() + self.defaults.0.get(binding).copied() } - fn defaults_or_fallback(&self) -> Shortcuts { - if self.defaults.0.is_empty() { - fallback_shortcuts() - } else { - self.defaults.clone() - } + pub fn reset_action(&mut self, reset_action: KeyBindAction) { + self.custom.0.retain(|binding, action| { + if *action == reset_action { + // Remove any matching bindings + return false; + } + if let Some(default_action) = self.defaults.0.get(binding) { + if *default_action == reset_action { + // Remove binding that overrode a default + return false; + } + } + true + }); } }