Skip to main content

rab/tui/
overlay.rs

1use crate::tui::Component;
2
3// =============================================================================
4// Overlay types — matching pi's packages/tui/src/tui.ts
5// =============================================================================
6
7/// Anchor position for overlays
8#[derive(Debug, Clone, Copy, PartialEq, Default)]
9pub enum OverlayAnchor {
10    #[default]
11    Center,
12    TopLeft,
13    TopRight,
14    BottomLeft,
15    BottomRight,
16    TopCenter,
17    BottomCenter,
18    LeftCenter,
19    RightCenter,
20}
21
22/// Margin configuration for overlays
23#[derive(Debug, Clone, Copy, Default)]
24pub struct OverlayMargin {
25    pub top: usize,
26    pub right: usize,
27    pub bottom: usize,
28    pub left: usize,
29}
30
31impl OverlayMargin {
32    pub fn uniform(value: usize) -> Self {
33        Self {
34            top: value,
35            right: value,
36            bottom: value,
37            left: value,
38        }
39    }
40}
41
42/// Value that can be absolute (number) or percentage (string like "50%").
43/// For simplicity in Rust, we represent percentage as f64 (0.0..=100.0).
44#[derive(Debug, Clone, Copy)]
45pub enum SizeValue {
46    Absolute(usize),
47    Percent(f64),
48}
49
50impl SizeValue {
51    pub fn resolve(&self, reference: usize) -> usize {
52        match self {
53            SizeValue::Absolute(v) => *v,
54            SizeValue::Percent(p) => {
55                let v = (reference as f64 * p / 100.0).floor() as usize;
56                v.max(1)
57            }
58        }
59    }
60}
61
62/// Options for overlay positioning and sizing.
63#[derive(Debug, Clone, Default)]
64pub struct OverlayOptions {
65    // === Sizing ===
66    /// Width in columns, or percentage of terminal width
67    pub width: Option<SizeValue>,
68    /// Minimum width in columns
69    pub min_width: Option<usize>,
70    /// Maximum height in rows, or percentage of terminal height
71    pub max_height: Option<SizeValue>,
72
73    // === Positioning - anchor-based ===
74    /// Anchor point for positioning (default: Center)
75    pub anchor: Option<OverlayAnchor>,
76    /// Horizontal offset from anchor position (positive = right)
77    pub offset_x: Option<isize>,
78    /// Vertical offset from anchor position (positive = down)
79    pub offset_y: Option<isize>,
80
81    // === Positioning - percentage or absolute ===
82    /// Row position: absolute number, or percentage from top
83    pub row: Option<SizeValue>,
84    /// Column position: absolute number, or percentage from left
85    pub col: Option<SizeValue>,
86
87    // === Margin from terminal edges ===
88    pub margin: Option<OverlayMargin>,
89
90    // === Visibility ===
91    /// If true, don't capture keyboard focus when shown
92    pub non_capturing: bool,
93}
94
95/// Internal entry in the overlay stack
96pub struct OverlayEntry {
97    pub component: Box<dyn Component>,
98    pub options: OverlayOptions,
99    /// Whether this overlay is temporarily hidden
100    pub hidden: bool,
101    /// Order for compositing (higher = on top)
102    pub focus_order: u64,
103    /// Unique ID for this overlay
104    pub id: u64,
105}
106
107/// Resolved overlay layout
108#[derive(Debug, Clone)]
109pub struct OverlayLayout {
110    pub width: usize,
111    pub row: usize,
112    pub col: usize,
113    pub max_height: Option<usize>,
114}