diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 0bced427007..0856dfde632 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -1191,55 +1191,181 @@ impl From for TouchId { /// Any events not covered by the filter are given to the widget, but are not exclusive. #[derive(Clone, Copy, Debug)] pub struct EventFilter { - /// If `true`, pressing tab will act on the widget, - /// and NOT move focus away from the focused widget. + /// If `true`, a copy action will be handled by the widget. /// - /// Default: `false` - pub tab: bool, + /// Default: `true` + pub copy: bool, + + /// If `true`, a cut action will be handled by the widget. + /// + /// Default: `true` + pub cut: bool, + + /// If `true`, a paste action will be handled by the widget. + /// + /// Default: `true` + pub paste: bool, /// If `true`, pressing horizontal arrows will act on the /// widget, and NOT move focus away from the focused widget. /// - /// Default: `false` - pub horizontal_arrows: bool, + /// Defaults to `false`, but is always `true` in the `TextEdit`. + pub horizontal_arrows_focus: bool, /// If `true`, pressing vertical arrows will act on the /// widget, and NOT move focus away from the focused widget. /// - /// Default: `false` - pub vertical_arrows: bool, + /// Defaults to `false`, but is always `true` in the `TextEdit`. + pub vertical_arrows_focus: bool, /// If `true`, pressing escape will act on the widget, /// and NOT surrender focus from the focused widget. /// /// Default: `false` - pub escape: bool, + pub escape_focus: bool, + + /// If `true`, pressing tab will act on the widget, + /// and NOT move focus away from the focused widget. + /// + /// Default: `false` + pub tab_focus: bool, + + /// Default: `true` + pub tab: bool, + + /// Default: `true` + pub home: bool, + + /// Default: `true` + pub end: bool, + + /// Default: `true` + pub pageup: bool, + + /// Default: `true` + pub pagedn: bool, + + /// Default: `true` + pub ctrl_home: bool, + + /// Default: `true` + pub ctrl_end: bool, + + /// Default: `true` + pub ctrl_arrowup: bool, + + /// Default: `true` + pub ctrl_arrowdown: bool, + + /// Default: `true` + pub ctrl_arrowleft: bool, + + /// Default: `true` + pub ctrl_arrowright: bool, + + /// Default: `true` + pub ctrl_a: bool, + + /// Default: `true` + pub ctrl_h: bool, + + /// Default: `true` + pub ctrl_k: bool, + + /// Default: `true` + pub ctrl_u: bool, + + /// Default: `true` + pub ctrl_w: bool, + + /// Default: `true` + pub ctrl_y: bool, + + /// Default: `true` + pub ctrl_z: bool, + + /// Default: `true` + pub shift_tab: bool, } #[allow(clippy::derivable_impls)] // let's be explicit impl Default for EventFilter { fn default() -> Self { Self { - tab: false, - horizontal_arrows: false, - vertical_arrows: false, - escape: false, + copy: true, + cut: true, + paste: true, + horizontal_arrows_focus: false, + vertical_arrows_focus: false, + escape_focus: false, + tab_focus: false, + tab: true, + home: true, + end: true, + pageup: true, + pagedn: true, + ctrl_arrowup: true, + ctrl_arrowdown: true, + ctrl_arrowleft: true, + ctrl_arrowright: true, + ctrl_home: true, + ctrl_end: true, + ctrl_a: true, + ctrl_h: true, + ctrl_k: true, + ctrl_u: true, + ctrl_w: true, + ctrl_y: true, + ctrl_z: true, + shift_tab: true, } } } impl EventFilter { + pub fn matches_focus(&self, event: &Event) -> bool { + match event { + Event::Key { key, modifiers, .. } => match key { + crate::Key::Escape => self.escape_focus, + crate::Key::Tab => self.tab_focus, + crate::Key::ArrowUp if modifiers.is_none() => self.vertical_arrows_focus, + crate::Key::ArrowDown if modifiers.is_none() => self.vertical_arrows_focus, + crate::Key::ArrowLeft if modifiers.is_none() => self.horizontal_arrows_focus, + crate::Key::ArrowRight if modifiers.is_none() => self.horizontal_arrows_focus, + _ => true, + }, + _ => true, + } + } + pub fn matches(&self, event: &Event) -> bool { - if let Event::Key { key, .. } = event { - match key { - crate::Key::Tab => self.tab, - crate::Key::ArrowUp | crate::Key::ArrowDown => self.vertical_arrows, - crate::Key::ArrowRight | crate::Key::ArrowLeft => self.horizontal_arrows, - crate::Key::Escape => self.escape, + match event { + Event::Copy => self.copy, + Event::Cut => self.cut, + Event::Paste(_) => self.paste, + Event::Key { key, modifiers, .. } => match key { + crate::Key::Tab if modifiers.is_none() => self.tab, + crate::Key::Home if modifiers.is_none() => self.home, + crate::Key::End if modifiers.is_none() => self.end, + crate::Key::PageUp if modifiers.is_none() => self.pageup, + crate::Key::PageDown if modifiers.is_none() => self.pagedn, + crate::Key::ArrowUp if modifiers.ctrl => self.ctrl_arrowup, + crate::Key::ArrowDown if modifiers.ctrl => self.ctrl_arrowdown, + crate::Key::ArrowLeft if modifiers.ctrl => self.ctrl_arrowleft, + crate::Key::ArrowRight if modifiers.ctrl => self.ctrl_arrowright, + crate::Key::Home if modifiers.ctrl => self.ctrl_home, + crate::Key::End if modifiers.ctrl => self.ctrl_end, + crate::Key::A if modifiers.ctrl => self.ctrl_a, + crate::Key::H if modifiers.ctrl => self.ctrl_h, + crate::Key::K if modifiers.ctrl => self.ctrl_k, + crate::Key::U if modifiers.ctrl => self.ctrl_u, + crate::Key::W if modifiers.ctrl => self.ctrl_w, + crate::Key::Y if modifiers.ctrl => self.ctrl_y, + crate::Key::Z if modifiers.ctrl => self.ctrl_z, + crate::Key::Tab if modifiers.shift => self.shift_tab, _ => true, - } - } else { - true + }, + _ => true, } } } diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index 2c669f0ffd8..d6cb81e793b 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -572,7 +572,7 @@ impl Focus { self.focus_direction = FocusDirection::None; for event in &new_input.events { - if !event_filter.matches(event) { + if !event_filter.matches_focus(event) { if let crate::Event::Key { key, pressed: true, @@ -581,10 +581,12 @@ impl Focus { } = event { if let Some(cardinality) = match key { - crate::Key::ArrowUp => Some(FocusDirection::Up), - crate::Key::ArrowRight => Some(FocusDirection::Right), - crate::Key::ArrowDown => Some(FocusDirection::Down), - crate::Key::ArrowLeft => Some(FocusDirection::Left), + crate::Key::ArrowUp if modifiers.is_none() => Some(FocusDirection::Up), + crate::Key::ArrowRight if modifiers.is_none() => { + Some(FocusDirection::Right) + } + crate::Key::ArrowDown if modifiers.is_none() => Some(FocusDirection::Down), + crate::Key::ArrowLeft if modifiers.is_none() => Some(FocusDirection::Left), crate::Key::Tab => { if modifiers.shift { diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index d535a5c7541..7be155a1a91 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -685,11 +685,14 @@ impl Slider<'_> { EventFilter { // pressing arrows in the orientation of the // slider should not move focus to next widget - horizontal_arrows: matches!( + horizontal_arrows_focus: matches!( self.orientation, SliderOrientation::Horizontal ), - vertical_arrows: matches!(self.orientation, SliderOrientation::Vertical), + vertical_arrows_focus: matches!( + self.orientation, + SliderOrientation::Vertical + ), ..Default::default() }, ); diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 2619035a4b9..c273fe93cc6 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -133,9 +133,9 @@ impl<'t> TextEdit<'t> { desired_height_rows: 4, event_filter: EventFilter { // moving the cursor is really important - horizontal_arrows: true, - vertical_arrows: true, - tab: false, // tab is used to change focus, not to insert a tab character + horizontal_arrows_focus: true, + vertical_arrows_focus: true, + tab_focus: false, // tab is used to change focus, not to insert a tab character ..Default::default() }, cursor_at_end: true, @@ -322,7 +322,7 @@ impl<'t> TextEdit<'t> { /// will insert the `'\t'` character. #[inline] pub fn lock_focus(mut self, tab_will_indent: bool) -> Self { - self.event_filter.tab = tab_will_indent; + self.event_filter.tab_focus = tab_will_indent; self } @@ -390,6 +390,15 @@ impl<'t> TextEdit<'t> { self.return_key = return_key.into(); self } + + /// Sets the event filter for this [`TextEdit`] instance. + #[inline] + pub fn event_filter(mut self, event_filter: EventFilter) -> Self { + self.event_filter = event_filter; + self.event_filter.horizontal_arrows_focus = true; + self.event_filter.vertical_arrows_focus = true; + self + } } // ----------------------------------------------------------------------------