Skip to main content

uzor_core/widgets/container/
input.rs

1//! Container input adapter - Contract/Connector for scrollbar event handling
2//!
3//! **ContainerInputHandler 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 container scrollbar events
10///
11/// This trait defines the contract for converting raw input events into scroll actions.
12/// External projects implement this trait to customize scroll behavior (rare).
13pub trait ContainerInputHandler {
14    // =========================================================================
15    // Hit Testing
16    // =========================================================================
17
18    /// Test if mouse position is inside scrollbar rect
19    fn hit_test_scrollbar(&self, scrollbar_rect: &Rect, mouse_pos: (f64, f64)) -> bool {
20        let (mouse_x, mouse_y) = mouse_pos;
21        mouse_x >= scrollbar_rect.x
22            && mouse_x <= scrollbar_rect.x + scrollbar_rect.width
23            && mouse_y >= scrollbar_rect.y
24            && mouse_y <= scrollbar_rect.y + scrollbar_rect.height
25    }
26
27    // =========================================================================
28    // Scroll Calculations
29    // =========================================================================
30
31    /// Convert mouse Y position to scroll offset (for drag scrolling)
32    fn mouse_to_scroll_offset(
33        &self,
34        mouse_y: f64,
35        scrollbar_y: f64,
36        scrollbar_height: f64,
37        content_height: f64,
38        viewport_height: f64,
39    ) -> f64 {
40        if scrollbar_height <= 0.0 {
41            return 0.0;
42        }
43
44        let max_scroll = (content_height - viewport_height).max(0.0);
45        let ratio = ((mouse_y - scrollbar_y) / scrollbar_height).clamp(0.0, 1.0);
46        ratio * max_scroll
47    }
48
49    /// Convert scroll wheel delta to scroll offset change
50    fn scroll_to_delta(&self, scroll_delta: f64, _viewport_height: f64) -> f64 {
51        scroll_delta * 40.0
52    }
53
54    /// Clamp scroll offset to valid range [0, max_scroll]
55    fn clamp_scroll_offset(
56        &self,
57        offset: f64,
58        content_height: f64,
59        viewport_height: f64,
60    ) -> f64 {
61        let max_scroll = (content_height - viewport_height).max(0.0);
62        offset.clamp(0.0, max_scroll)
63    }
64
65    // =========================================================================
66    // Scrollbar Thumb Sizing
67    // =========================================================================
68
69    /// Calculate scrollbar thumb size based on viewport/content ratio
70    fn calculate_thumb_size(
71        &self,
72        viewport_height: f64,
73        content_height: f64,
74        scrollbar_height: f64,
75        min_thumb_height: f64,
76    ) -> f64 {
77        if content_height <= 0.0 || viewport_height >= content_height {
78            return scrollbar_height;
79        }
80
81        let ratio = viewport_height / content_height;
82        let thumb_height = ratio * scrollbar_height;
83        thumb_height.max(min_thumb_height)
84    }
85
86    /// Calculate scrollbar thumb Y position based on scroll offset
87    fn calculate_thumb_position(
88        &self,
89        scroll_offset: f64,
90        content_height: f64,
91        viewport_height: f64,
92        scrollbar_y: f64,
93        scrollbar_height: f64,
94        thumb_height: f64,
95    ) -> f64 {
96        let max_scroll = (content_height - viewport_height).max(0.0);
97        if max_scroll <= 0.0 {
98            return scrollbar_y;
99        }
100
101        let scroll_ratio = (scroll_offset / max_scroll).clamp(0.0, 1.0);
102        let max_thumb_travel = scrollbar_height - thumb_height;
103        scrollbar_y + scroll_ratio * max_thumb_travel
104    }
105}
106
107// =============================================================================
108// Default Input Handler Implementation
109// =============================================================================
110
111/// Default implementation of ContainerInputHandler
112#[derive(Clone, Copy, Debug, Default)]
113pub struct DefaultContainerInputHandler;
114
115impl ContainerInputHandler for DefaultContainerInputHandler {
116    // All methods use trait defaults (no overrides needed)
117}