From 10440031796885eb09988127e118ccacb2e1c267 Mon Sep 17 00:00:00 2001 From: filipriec_vm Date: Sun, 11 Jan 2026 16:03:04 +0100 Subject: [PATCH] working focus --- examples/focus_advanced.rs | 57 ++++++++++++++++++++++++++++++++++++++ src/focus/builder.rs | 26 +++++++++++++++++ src/focus/id.rs | 2 -- src/focus/manager.rs | 35 +++++++++++++++++++++++ src/focus/mode.rs | 9 ++++++ src/focus/navigation.rs | 11 ++++++++ 6 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 examples/focus_advanced.rs create mode 100644 src/focus/builder.rs create mode 100644 src/focus/mode.rs create mode 100644 src/focus/navigation.rs diff --git a/examples/focus_advanced.rs b/examples/focus_advanced.rs new file mode 100644 index 0000000..dd8e676 --- /dev/null +++ b/examples/focus_advanced.rs @@ -0,0 +1,57 @@ +extern crate alloc; + +use tui_orchestrator::focus::{FocusBuilder, FocusId, FocusManager, Focusable}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum FormElement { + Username, + Password, + RememberMe, + Submit, +} + +struct FormPage { + username: alloc::string::String, + password: alloc::string::String, + remember: bool, +} + +impl Focusable for FormPage { + fn focus_targets(&self) -> alloc::vec::Vec { + alloc::vec![ + FormElement::Username, + FormElement::Password, + FormElement::RememberMe, + FormElement::Submit, + ] + } +} + +fn main() { + let form = FormPage { + username: alloc::string::String::new(), + password: alloc::string::String::new(), + remember: false, + }; + + let mut focus_manager = FocusManager::new(); + focus_manager.set_targets(form.focus_targets()); + println!("Current focus: {:?}", focus_manager.current()); + + focus_manager.next(); + println!("After next: {:?}", focus_manager.current()); + + focus_manager.last(); + println!("After last: {:?}", focus_manager.current()); + + println!("Is first: {}", focus_manager.is_first()); + println!("Is last: {}", focus_manager.is_last()); + + println!("\n--- FocusBuilder Demo ---"); + let builder = FocusBuilder::new() + .target(FormElement::Username) + .target(FormElement::Password) + .target(FormElement::Submit); + let targets = builder.build(); + println!("Built targets: {:?}", targets); +} diff --git a/src/focus/builder.rs b/src/focus/builder.rs new file mode 100644 index 0000000..317c2e4 --- /dev/null +++ b/src/focus/builder.rs @@ -0,0 +1,26 @@ +#[derive(Debug, Clone, Default)] +pub struct FocusBuilder { + targets: alloc::vec::Vec, +} + +impl FocusBuilder { + pub fn new() -> Self { + Self { + targets: alloc::vec::Vec::new(), + } + } + + pub fn target(mut self, target: F) -> Self { + self.targets.push(target); + self + } + + pub fn targets(mut self, targets: &[F]) -> Self { + self.targets.extend_from_slice(targets); + self + } + + pub fn build(self) -> alloc::vec::Vec { + self.targets + } +} diff --git a/src/focus/id.rs b/src/focus/id.rs index 68afad6..99ccc1c 100644 --- a/src/focus/id.rs +++ b/src/focus/id.rs @@ -1,5 +1,3 @@ // path_from_the_root: src/focus/id.rs pub trait FocusId: Clone + PartialEq + Eq + core::hash::Hash {} - -impl FocusId for T {} diff --git a/src/focus/manager.rs b/src/focus/manager.rs index b90dac1..2876bce 100644 --- a/src/focus/manager.rs +++ b/src/focus/manager.rs @@ -133,4 +133,39 @@ impl FocusManager { pub fn is_empty(&self) -> bool { self.targets.is_empty() } + + pub fn current_index(&self) -> Option { + if self.targets.is_empty() { + None + } else { + Some(self.index) + } + } + + pub fn wrap_next(&mut self) { + if !self.targets.is_empty() { + self.index = (self.index + 1) % self.targets.len(); + } + } + + pub fn wrap_prev(&mut self) { + if !self.targets.is_empty() { + self.index = if self.index == 0 { + self.targets.len() - 1 + } else { + self.index - 1 + }; + } + } + + pub fn is_first(&self) -> bool { + self.current_index() == Some(0) + } + + pub fn is_last(&self) -> bool { + match self.current_index() { + Some(idx) => idx == self.targets.len().saturating_sub(1), + None => false, + } + } } diff --git a/src/focus/mode.rs b/src/focus/mode.rs new file mode 100644 index 0000000..899d4e1 --- /dev/null +++ b/src/focus/mode.rs @@ -0,0 +1,9 @@ +pub trait FocusModeHint { + fn focus_modes(&self) -> &[&'static str]; +} + +impl FocusModeHint for super::FocusManager { + fn focus_modes(&self) -> &[&'static str] { + &["general"] + } +} diff --git a/src/focus/navigation.rs b/src/focus/navigation.rs new file mode 100644 index 0000000..9df31b9 --- /dev/null +++ b/src/focus/navigation.rs @@ -0,0 +1,11 @@ +pub trait FocusNavigation { + type Error; + + fn can_navigate_forward(&self, from: &F) -> bool; + + fn can_navigate_backward(&self, from: &F) -> bool; + + fn navigate_forward(&mut self) -> Result, Self::Error>; + + fn navigate_backward(&mut self) -> Result, Self::Error>; +}