diff options
author | 2022-08-02 04:20:47 +0200 | |
---|---|---|
committer | 2022-08-02 04:20:47 +0200 | |
commit | 77c6864e7c772c5e228bc09fe40c2c0b8884386d (patch) | |
tree | bad8540154db00567937a2e357e3bd271b509f23 /native/src | |
parent | 6dac049db5824e3af06bc16df0fdf51f8809aeb4 (diff) | |
download | iced-77c6864e7c772c5e228bc09fe40c2c0b8884386d.tar.gz iced-77c6864e7c772c5e228bc09fe40c2c0b8884386d.tar.bz2 iced-77c6864e7c772c5e228bc09fe40c2c0b8884386d.zip |
Implement `focus_next` operation
... as well as a `count_focusable` composable helper!
Diffstat (limited to 'native/src')
-rw-r--r-- | native/src/widget/operation.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index 2cfba005..5a0f0c18 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -58,3 +58,96 @@ pub fn focus<T>(target: Id) -> impl Operation<T> { Focus { target } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct FocusCount { + focused: Option<usize>, + total: usize, +} + +pub fn count_focusable<T, O>(f: fn(FocusCount) -> O) -> impl Operation<T> +where + O: Operation<T> + 'static, +{ + struct CountFocusable<O> { + count: FocusCount, + next: fn(FocusCount) -> O, + } + + impl<T, O> Operation<T> for CountFocusable<O> + where + O: Operation<T> + 'static, + { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { + if state.is_focused() { + self.count.focused = Some(self.count.total); + } + + self.count.total += 1; + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), + ) { + operate_on_children(self) + } + + fn finish(&self) -> Outcome<T> { + Outcome::Chain(Box::new((self.next)(self.count))) + } + } + + CountFocusable { + count: FocusCount::default(), + next: f, + } +} + +pub fn focus_next<T>() -> impl Operation<T> { + struct FocusNext { + count: FocusCount, + current: usize, + } + + impl<T> Operation<T> for FocusNext { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { + if self.count.total == 0 { + return; + } + + match self.count.focused { + None if self.current == 0 => state.focus(), + Some(focused) if focused == self.current => state.unfocus(), + Some(focused) if focused + 1 == self.current => state.focus(), + Some(focused) + if focused == self.count.total - 1 && self.current == 0 => + { + state.focus() + } + _ => {} + } + + self.current += 1; + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), + ) { + operate_on_children(self) + } + } + + count_focusable(|count| FocusNext { count, current: 0 }) +} |