uzor_core/widgets/button/input.rs
1//! Button input adapter - Contract/Connector for button event handling
2//!
3//! **ButtonInputHandler is a CONTRACT/CONNECTOR trait** that connects:
4//! - Factory event handling logic (`factory/events.rs` - future)
5//! - External input systems (event loops, input managers, etc.)
6
7use crate::types::Rect;
8
9/// Input handler adapter for button events
10///
11/// This trait defines the contract for converting raw input events into button actions.
12/// External projects implement this trait to customize input behavior (rare).
13pub trait ButtonInputHandler {
14 // =========================================================================
15 // Hit Testing
16 // =========================================================================
17
18 /// Test if mouse position is inside button rect
19 fn hit_test(&self, mouse_x: f64, mouse_y: f64, rect: &Rect) -> bool {
20 mouse_x >= rect.x
21 && mouse_x <= rect.x + rect.width
22 && mouse_y >= rect.y
23 && mouse_y <= rect.y + rect.height
24 }
25
26 // =========================================================================
27 // Click Detection
28 // =========================================================================
29
30 /// Detect if button was clicked
31 fn is_click(
32 &self,
33 press_x: f64,
34 press_y: f64,
35 release_x: f64,
36 release_y: f64,
37 rect: &Rect
38 ) -> bool {
39 self.hit_test(press_x, press_y, rect)
40 && self.hit_test(release_x, release_y, rect)
41 }
42
43 // =========================================================================
44 // Keyboard Navigation
45 // =========================================================================
46
47 /// Get next focus target when Tab is pressed
48 fn next_focus(&self, current_id: &str, all_ids: &[String]) -> String {
49 if all_ids.is_empty() {
50 return String::new();
51 }
52
53 if let Some(idx) = all_ids.iter().position(|id| id == current_id) {
54 let next_idx = (idx + 1) % all_ids.len();
55 all_ids[next_idx].clone()
56 } else {
57 // Current not found, return first
58 all_ids[0].clone()
59 }
60 }
61
62 /// Get previous focus target when Shift+Tab is pressed
63 fn prev_focus(&self, current_id: &str, all_ids: &[String]) -> String {
64 if all_ids.is_empty() {
65 return String::new();
66 }
67
68 if let Some(idx) = all_ids.iter().position(|id| id == current_id) {
69 let prev_idx = if idx == 0 {
70 all_ids.len() - 1
71 } else {
72 idx - 1
73 };
74 all_ids[prev_idx].clone()
75 } else {
76 // Current not found, return last
77 all_ids[all_ids.len() - 1].clone()
78 }
79 }
80
81 // =========================================================================
82 // Activation Keys
83 // =========================================================================
84
85 /// Check if key activates button (like click)
86 fn is_activation_key(&self, key: &str) -> bool {
87 key == "Enter" || key == "Space" || key == " "
88 }
89}
90
91// =============================================================================
92// Default Input Handler Implementation
93// =============================================================================
94
95/// Default implementation of ButtonInputHandler
96#[derive(Clone, Copy, Debug, Default)]
97pub struct DefaultButtonInputHandler;
98
99impl ButtonInputHandler for DefaultButtonInputHandler {
100 // All methods use trait defaults (no overrides needed)
101}