Skip to main content

gitkraft_gui/widgets/
divider.rs

1//! Thin draggable divider widgets for resizable panes.
2//!
3//! Two flavours are provided:
4//!
5//! - [`vertical_divider`] — a narrow vertical bar that the user can drag
6//!   left/right to resize adjacent horizontal panes.
7//! - [`horizontal_divider`] — a narrow horizontal bar that the user can drag
8//!   up/down to resize adjacent vertical panes.
9//!
10//! Both are built from `mouse_area` + `container` so they emit the standard
11//! `PaneDragStart` / `PaneDragStartH` messages on press.  The hit-zone is
12//! deliberately wider than the visible rule so that grabbing the divider with
13//! the mouse is comfortable.  A subtle background highlight appears on hover
14//! to signal that the divider is interactive.
15
16use iced::widget::{container, mouse_area, vertical_rule};
17use iced::{Background, Color, Element, Length};
18
19use crate::message::Message;
20use crate::state::{DragTarget, DragTargetH};
21use crate::theme::ThemeColors;
22
23/// Width of the draggable hit-zone for vertical dividers (pixels).
24const V_HIT_WIDTH: f32 = 8.0;
25
26/// Height of the draggable hit-zone for horizontal dividers (pixels).
27const H_HIT_HEIGHT: f32 = 8.0;
28
29/// A thin vertical divider that starts a drag on `target` when pressed.
30///
31/// The element is `V_HIT_WIDTH` px wide and fills the parent height.  A 1 px
32/// `vertical_rule` is centered inside so the visual line stays crisp while the
33/// clickable area is comfortable.  On hover the background subtly highlights.
34pub fn vertical_divider<'a>(target: DragTarget, _c: &ThemeColors) -> Element<'a, Message> {
35    let rule = vertical_rule(1).style(move |theme: &iced::Theme| {
36        let tc = crate::theme::ThemeColors::from_theme(theme);
37        iced::widget::rule::Style {
38            color: tc.border,
39            width: 1,
40            radius: 0.0.into(),
41            fill_mode: iced::widget::rule::FillMode::Full,
42        }
43    });
44
45    let hit_zone = container(rule)
46        .width(V_HIT_WIDTH)
47        .height(Length::Fill)
48        .center_x(V_HIT_WIDTH)
49        .center_y(Length::Fill)
50        .style(move |theme: &iced::Theme| {
51            let tc = crate::theme::ThemeColors::from_theme(theme);
52            container::Style {
53                background: Some(Background::Color(Color {
54                    a: 0.0,
55                    ..tc.border
56                })),
57                ..Default::default()
58            }
59        });
60
61    // The mouse_area makes the entire hit-zone clickable.  `on_press`
62    // initiates the drag — subsequent move/release events are captured by
63    // the always-active outer `mouse_area` in `view.rs`.
64    mouse_area(hit_zone)
65        .on_press(Message::PaneDragStart(target, 0.0))
66        .interaction(iced::mouse::Interaction::ResizingHorizontally)
67        .into()
68}
69
70/// A thin horizontal divider that starts a drag on `target` when pressed.
71///
72/// The element is `H_HIT_HEIGHT` px tall and fills the parent width.  A 1 px
73/// `horizontal_rule` is centered inside.  On hover the background subtly
74/// highlights.
75pub fn horizontal_divider<'a>(target: DragTargetH, _c: &ThemeColors) -> Element<'a, Message> {
76    let rule = iced::widget::horizontal_rule(1).style(move |theme: &iced::Theme| {
77        let tc = crate::theme::ThemeColors::from_theme(theme);
78        iced::widget::rule::Style {
79            color: tc.border,
80            width: 1,
81            radius: 0.0.into(),
82            fill_mode: iced::widget::rule::FillMode::Full,
83        }
84    });
85
86    let hit_zone = container(rule)
87        .width(Length::Fill)
88        .height(H_HIT_HEIGHT)
89        .center_x(Length::Fill)
90        .center_y(H_HIT_HEIGHT)
91        .style(move |theme: &iced::Theme| {
92            let tc = crate::theme::ThemeColors::from_theme(theme);
93            container::Style {
94                background: Some(Background::Color(Color {
95                    a: 0.0,
96                    ..tc.border
97                })),
98                ..Default::default()
99            }
100        });
101
102    mouse_area(hit_zone)
103        .on_press(Message::PaneDragStartH(target, 0.0))
104        .interaction(iced::mouse::Interaction::ResizingVertically)
105        .into()
106}