summaryrefslogtreecommitdiffstats
path: root/native
diff options
context:
space:
mode:
Diffstat (limited to 'native')
-rw-r--r--native/src/widget/operation.rs93
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 })
+}