git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

src/widget/display/splitter.rs (2.7K)

 1 //! Narrow-trait pane splitter (Phase 5i leaf sweep). A self-moving widget: dragging repositions
 2 //! the splitter itself via [`Input::drag_reposition`] (the adapter applies the new origin to the
 3 //! base rect). Hover/drag drive the color, tracked from the forwarded events.
 4 
 5 use crate::colors;
 6 use crate::scene::layout::Rect;
 7 use crate::scene::paint::PaintCtx;
 8 use crate::widget::{Adapted, WidgetHost, ElementState, Event, EventCtx, Input, Layout, MouseButton, Paint};
 9 
10 pub struct Splitter {
11     hovered: bool,
12     dragging: bool,
13     drag_ox: f32,
14 }
15 
16 impl Splitter {
17     pub fn new(w: f32) -> Adapted<Splitter> {
18         let mut s = Adapted::new(Splitter { hovered: false, dragging: false, drag_ox: 0.0 });
19         WidgetHost::set_rect(&mut s, 0.0, 0.0, w, 0.0);
20         s
21     }
22 }
23 
24 impl Layout for Splitter {}
25 
26 impl Paint for Splitter {
27     fn color(&self) -> [f32; 4] {
28         if self.dragging {
29             colors::SPLITTER_DRAG
30         } else if self.hovered {
31             colors::SPLITTER_HOVER
32         } else {
33             colors::SPLITTER_IDLE
34         }
35     }
36 
37     /// The bar as a capsule: fully rounded ends on its short side.
38     fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
39         let color = self.color();
40         if color[3].abs() > 0.001 {
41             let r = rect.width.min(rect.height) * 0.5;
42             ctx.rounded_rect(rect, r, (true, true, true, true), color);
43         }
44     }
45 }
46 
47 impl Input for Splitter {
48     fn on_event(&mut self, event: &Event, ectx: &mut EventCtx) -> bool {
49         match event {
50             Event::MouseButton { button: MouseButton::Left, state: ElementState::Pressed, x, .. } => {
51                 self.dragging = true;
52                 self.drag_ox = x - ectx.rect.x;
53                 true
54             }
55             Event::MouseButton { button: MouseButton::Left, state: ElementState::Released, .. } => {
56                 std::mem::take(&mut self.dragging)
57             }
58             Event::MouseEnter => {
59                 self.hovered = true;
60                 false
61             }
62             Event::MouseLeave => {
63                 self.hovered = false;
64                 false
65             }
66             _ => false,
67         }
68     }
69 
70     fn draggable(&self, _rect: Rect) -> bool {
71         true
72     }
73     fn is_dragging(&self) -> bool {
74         self.dragging
75     }
76     fn drag_begin(&mut self, px: f32, _py: f32, rect: Rect) {
77         self.dragging = true;
78         self.drag_ox = px - rect.x;
79     }
80     fn drag_reposition(&mut self, px: f32, _py: f32, rect: Rect) -> Option<(f32, f32)> {
81         let new_x = px - self.drag_ox;
82         if (new_x - rect.x).abs() > 0.5 {
83             Some((new_x, rect.y))
84         } else {
85             None
86         }
87     }
88     fn drag_end(&mut self) {
89         self.dragging = false;
90     }
91 }