Skip to main content

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}