Skip to main content

gitkraft_gui/
layout.rs

1//! Responsive layout: pure functions mapping window size + stored pane sizes
2//! to the sizes actually rendered. Stored sizes are never modified.
3
4/// Below this window width the sidebar is hidden.
5pub const NARROW_WIDTH: f32 = 720.0;
6/// Max sidebar share of window width.
7pub const SIDEBAR_MAX_FRAC: f32 = 0.35;
8/// Max commit-log share of width remaining after the sidebar.
9pub const COMMIT_MAX_FRAC: f32 = 0.55;
10/// Max staging-area share of window height.
11pub const STAGING_MAX_FRAC: f32 = 0.5;
12
13/// Pane sizes to render.
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub struct LayoutDims {
16    /// Sidebar docked beside the panes.
17    pub show_sidebar: bool,
18    /// Sidebar expanded but window narrow: float it over the panes.
19    pub overlay_sidebar: bool,
20    pub sidebar_width: f32,
21    pub commit_log_width: f32,
22    pub staging_height: f32,
23}
24
25impl LayoutDims {
26    pub fn compute(
27        window_w: f32,
28        window_h: f32,
29        sidebar_expanded: bool,
30        sidebar_w: f32,
31        commit_w: f32,
32        staging_h: f32,
33    ) -> Self {
34        let show_sidebar = sidebar_expanded && window_w >= NARROW_WIDTH;
35        let overlay_sidebar = sidebar_expanded && !show_sidebar;
36        let sidebar_width = sidebar_w.min(window_w * SIDEBAR_MAX_FRAC).max(0.0);
37        let used = if show_sidebar { sidebar_width } else { 0.0 };
38        Self {
39            show_sidebar,
40            overlay_sidebar,
41            sidebar_width,
42            commit_log_width: commit_w.min((window_w - used) * COMMIT_MAX_FRAC).max(0.0),
43            staging_height: staging_h.min(window_h * STAGING_MAX_FRAC).max(0.0),
44        }
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    fn dims(w: f32, h: f32, exp: bool) -> LayoutDims {
53        LayoutDims::compute(w, h, exp, 250.0, 600.0, 300.0)
54    }
55
56    #[test]
57    fn wide_window_keeps_stored_sizes() {
58        let d = dims(1920.0, 1080.0, true);
59        assert!(d.show_sidebar);
60        assert_eq!(d.sidebar_width, 250.0);
61        assert_eq!(d.commit_log_width, 600.0);
62        assert_eq!(d.staging_height, 300.0);
63    }
64
65    #[test]
66    fn narrow_window_hides_sidebar() {
67        assert!(!dims(NARROW_WIDTH - 1.0, 800.0, true).show_sidebar);
68        assert!(dims(NARROW_WIDTH, 800.0, true).show_sidebar);
69    }
70
71    #[test]
72    fn narrow_expanded_sidebar_overlays() {
73        let d = dims(600.0, 800.0, true);
74        assert!(d.overlay_sidebar && !d.show_sidebar);
75        assert!(!dims(1200.0, 800.0, true).overlay_sidebar);
76        assert!(!dims(600.0, 800.0, false).overlay_sidebar);
77    }
78
79    #[test]
80    fn collapsed_sidebar_stays_hidden() {
81        assert!(!dims(1920.0, 1080.0, false).show_sidebar);
82    }
83
84    #[test]
85    fn sidebar_and_commit_clamped() {
86        let d = LayoutDims::compute(800.0, 800.0, true, 400.0, 900.0, 300.0);
87        assert_eq!(d.sidebar_width, 280.0); // capped: 35% of 800
88        assert!(d.commit_log_width <= (800.0 - d.sidebar_width) * COMMIT_MAX_FRAC);
89    }
90
91    #[test]
92    fn commit_uses_full_width_when_sidebar_hidden() {
93        let d = dims(600.0, 800.0, true);
94        assert_eq!(d.commit_log_width, 330.0);
95    }
96
97    #[test]
98    fn staging_clamped_to_half_height() {
99        assert_eq!(dims(1200.0, 400.0, true).staging_height, 200.0);
100    }
101
102    #[test]
103    fn tiny_window_never_negative() {
104        let d = dims(0.0, 0.0, true);
105        assert!(d.sidebar_width >= 0.0 && d.commit_log_width >= 0.0 && d.staging_height >= 0.0);
106    }
107}