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
+ });
}
}