add dialog box when replacing existing keybind
This commit is contained in:
parent
cc27b6ab30
commit
70e0f5a5f2
3 changed files with 116 additions and 2 deletions
|
|
@ -67,6 +67,9 @@ keyboard-shortcuts = Keyboard shortcuts
|
||||||
customize-shortcuts = Customize shortcuts
|
customize-shortcuts = Customize shortcuts
|
||||||
shortcut-capture-hint = Press new shortcut, or Esc to cancel
|
shortcut-capture-hint = Press new shortcut, or Esc to cancel
|
||||||
cancel = Cancel
|
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
|
no-shortcuts = No shortcuts
|
||||||
add-shortcut = + Add
|
add-shortcut = + Add
|
||||||
shortcut-group-clipboard = Clipboard
|
shortcut-group-clipboard = Clipboard
|
||||||
|
|
|
||||||
103
src/main.rs
103
src/main.rs
|
|
@ -377,6 +377,8 @@ pub enum Message {
|
||||||
Modifiers(Modifiers),
|
Modifiers(Modifiers),
|
||||||
ShortcutCaptureCancel,
|
ShortcutCaptureCancel,
|
||||||
ShortcutCaptureStart(shortcuts::KeyBindAction),
|
ShortcutCaptureStart(shortcuts::KeyBindAction),
|
||||||
|
ShortcutConflictCancel,
|
||||||
|
ShortcutConflictReplace,
|
||||||
ShortcutRemove(shortcuts::Binding, shortcuts::BindingSource),
|
ShortcutRemove(shortcuts::Binding, shortcuts::BindingSource),
|
||||||
MouseEnter(pane_grid::Pane),
|
MouseEnter(pane_grid::Pane),
|
||||||
Opacity(u8),
|
Opacity(u8),
|
||||||
|
|
@ -444,6 +446,13 @@ pub enum ContextPage {
|
||||||
PasswordManager,
|
PasswordManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct ShortcutConflict {
|
||||||
|
binding: shortcuts::Binding,
|
||||||
|
existing_action: shortcuts::KeyBindAction,
|
||||||
|
new_action: shortcuts::KeyBindAction,
|
||||||
|
}
|
||||||
|
|
||||||
/// The [`App`] stores application-specific state.
|
/// The [`App`] stores application-specific state.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
core: Core,
|
core: Core,
|
||||||
|
|
@ -488,6 +497,8 @@ pub struct App {
|
||||||
show_advanced_font_settings: bool,
|
show_advanced_font_settings: bool,
|
||||||
show_keyboard_shortcuts: bool,
|
show_keyboard_shortcuts: bool,
|
||||||
shortcut_capture: Option<shortcuts::KeyBindAction>,
|
shortcut_capture: Option<shortcuts::KeyBindAction>,
|
||||||
|
shortcut_conflict: Option<ShortcutConflict>,
|
||||||
|
shortcut_conflict_overlay_restore: Option<bool>,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
password_mgr: password_manager::PasswordManager,
|
password_mgr: password_manager::PasswordManager,
|
||||||
|
|
@ -577,6 +588,37 @@ impl App {
|
||||||
self.key_binds = key_binds(&self.shortcuts_config);
|
self.key_binds = key_binds(&self.shortcuts_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_shortcut_binding(
|
||||||
|
&mut self,
|
||||||
|
binding: shortcuts::Binding,
|
||||||
|
action: shortcuts::KeyBindAction,
|
||||||
|
) {
|
||||||
|
self.shortcuts_config.custom.0.insert(binding, action);
|
||||||
|
self.save_shortcuts_custom();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_context_overlay(&mut self, overlay: bool) {
|
||||||
|
if self.core.window.context_is_overlay != overlay {
|
||||||
|
self.core.window.context_is_overlay = overlay;
|
||||||
|
self.core.set_show_context(self.core.window.show_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_shortcut_conflict(&mut self, conflict: ShortcutConflict) {
|
||||||
|
if self.shortcut_conflict.is_none() {
|
||||||
|
self.shortcut_conflict_overlay_restore = Some(self.core.window.context_is_overlay);
|
||||||
|
self.set_context_overlay(false);
|
||||||
|
}
|
||||||
|
self.shortcut_conflict = Some(conflict);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_shortcut_conflict(&mut self) {
|
||||||
|
self.shortcut_conflict = None;
|
||||||
|
if let Some(overlay) = self.shortcut_conflict_overlay_restore.take() {
|
||||||
|
self.set_context_overlay(overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_config(&mut self) -> Task<Message> {
|
fn update_config(&mut self) -> Task<Message> {
|
||||||
let theme = self.config.app_theme.theme();
|
let theme = self.config.app_theme.theme();
|
||||||
|
|
||||||
|
|
@ -1744,6 +1786,8 @@ impl Application for App {
|
||||||
show_advanced_font_settings: false,
|
show_advanced_font_settings: false,
|
||||||
show_keyboard_shortcuts: false,
|
show_keyboard_shortcuts: false,
|
||||||
shortcut_capture: None,
|
shortcut_capture: None,
|
||||||
|
shortcut_conflict: None,
|
||||||
|
shortcut_conflict_overlay_restore: None,
|
||||||
modifiers: Modifiers::empty(),
|
modifiers: Modifiers::empty(),
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
password_mgr: Default::default(),
|
password_mgr: Default::default(),
|
||||||
|
|
@ -2284,6 +2328,12 @@ impl Application for App {
|
||||||
config_set!(focus_follow_mouse, focus_follow_mouse);
|
config_set!(focus_follow_mouse, focus_follow_mouse);
|
||||||
}
|
}
|
||||||
Message::Key(modifiers, key) => {
|
Message::Key(modifiers, key) => {
|
||||||
|
if self.shortcut_conflict.is_some() {
|
||||||
|
if key == Key::Named(Named::Escape) {
|
||||||
|
self.clear_shortcut_conflict();
|
||||||
|
}
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
if let Some(action) = self.shortcut_capture {
|
if let Some(action) = self.shortcut_capture {
|
||||||
if key == Key::Named(Named::Escape) {
|
if key == Key::Named(Named::Escape) {
|
||||||
self.shortcut_capture = None;
|
self.shortcut_capture = None;
|
||||||
|
|
@ -2291,8 +2341,20 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
if let Some(binding) = shortcuts::binding_from_key(modifiers, key) {
|
if let Some(binding) = shortcuts::binding_from_key(modifiers, key) {
|
||||||
self.shortcut_capture = None;
|
self.shortcut_capture = None;
|
||||||
self.shortcuts_config.custom.0.insert(binding, action);
|
if let Some(existing_action) =
|
||||||
self.save_shortcuts_custom();
|
self.shortcuts_config.action_for_binding(&binding)
|
||||||
|
{
|
||||||
|
if existing_action != action {
|
||||||
|
self.begin_shortcut_conflict(ShortcutConflict {
|
||||||
|
binding,
|
||||||
|
existing_action,
|
||||||
|
new_action: action,
|
||||||
|
});
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
self.apply_shortcut_binding(binding, action);
|
||||||
}
|
}
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
@ -2337,6 +2399,15 @@ impl Application for App {
|
||||||
Message::ShortcutCaptureStart(action) => {
|
Message::ShortcutCaptureStart(action) => {
|
||||||
self.shortcut_capture = Some(action);
|
self.shortcut_capture = Some(action);
|
||||||
}
|
}
|
||||||
|
Message::ShortcutConflictCancel => {
|
||||||
|
self.clear_shortcut_conflict();
|
||||||
|
}
|
||||||
|
Message::ShortcutConflictReplace => {
|
||||||
|
if let Some(conflict) = self.shortcut_conflict.clone() {
|
||||||
|
self.apply_shortcut_binding(conflict.binding, conflict.new_action);
|
||||||
|
}
|
||||||
|
self.clear_shortcut_conflict();
|
||||||
|
}
|
||||||
Message::ShortcutRemove(binding, source) => {
|
Message::ShortcutRemove(binding, source) => {
|
||||||
match source {
|
match source {
|
||||||
shortcuts::BindingSource::Default => {
|
shortcuts::BindingSource::Default => {
|
||||||
|
|
@ -2988,6 +3059,34 @@ impl Application for App {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dialog(&self) -> Option<Element<'_, Message>> {
|
||||||
|
let conflict = self.shortcut_conflict.as_ref()?;
|
||||||
|
let binding = shortcuts::binding_display(&conflict.binding);
|
||||||
|
let existing = shortcuts::action_label(conflict.existing_action);
|
||||||
|
let new_action = shortcuts::action_label(conflict.new_action);
|
||||||
|
let body = fl!(
|
||||||
|
"shortcut-replace-body",
|
||||||
|
binding = binding.as_str(),
|
||||||
|
existing = existing.as_str(),
|
||||||
|
new_action = new_action.as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(
|
||||||
|
widget::dialog()
|
||||||
|
.title(fl!("shortcut-replace-title"))
|
||||||
|
.body(body)
|
||||||
|
.primary_action(
|
||||||
|
widget::button::suggested(fl!("replace"))
|
||||||
|
.on_press(Message::ShortcutConflictReplace),
|
||||||
|
)
|
||||||
|
.secondary_action(
|
||||||
|
widget::button::standard(fl!("cancel"))
|
||||||
|
.on_press(Message::ShortcutConflictCancel),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn header_start(&self) -> Vec<Element<'_, Self::Message>> {
|
fn header_start(&self) -> Vec<Element<'_, Self::Message>> {
|
||||||
vec![menu_bar(&self.core, &self.config, &self.key_binds)]
|
vec![menu_bar(&self.core, &self.config, &self.key_binds)]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,18 @@ impl ShortcutsConfig {
|
||||||
bindings
|
bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn action_for_binding(&self, binding: &Binding) -> Option<KeyBindAction> {
|
||||||
|
if let Some(action) = self.custom.0.get(binding) {
|
||||||
|
if *action == KeyBindAction::Unbind {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(*action);
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaults = self.defaults_or_fallback();
|
||||||
|
defaults.0.get(binding).copied()
|
||||||
|
}
|
||||||
|
|
||||||
fn defaults_or_fallback(&self) -> Shortcuts {
|
fn defaults_or_fallback(&self) -> Shortcuts {
|
||||||
if self.defaults.0.is_empty() {
|
if self.defaults.0.is_empty() {
|
||||||
fallback_shortcuts()
|
fallback_shortcuts()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue