Skip to main content

edb_tui/
layout.rs

1// EDB - Ethereum Debugger
2// Copyright (C) 2024 Zhuo Zhang and Wuqi Zhang
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17//! Adaptive layout management
18//!
19//! This module handles responsive layout switching based on terminal size.
20
21/// Configuration for layout manager
22#[derive(Debug, Clone, Default)]
23pub struct LayoutConfig {
24    /// Enable mouse support
25    pub enable_mouse: bool,
26}
27
28/// Layout types for different terminal sizes
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum LayoutType {
31    /// Full 4-panel quad layout (≥120 columns)
32    Full,
33    /// Compact 3-panel stacked layout (80-119 columns)
34    Compact,
35    /// Single panel mode with F-key switching (<80 columns)
36    Mobile,
37}
38
39/// Layout manager for responsive design
40#[derive(Debug)]
41pub struct LayoutManager {
42    current_layout: LayoutType,
43    terminal_width: u16,
44    terminal_height: u16,
45}
46
47impl LayoutManager {
48    /// Create a new layout manager with default values
49    pub fn new() -> Self {
50        Self { current_layout: LayoutType::Full, terminal_width: 80, terminal_height: 24 }
51    }
52
53    /// Update terminal dimensions and recalculate layout
54    pub fn update_size(&mut self, width: u16, height: u16) {
55        self.terminal_width = width;
56        self.terminal_height = height;
57        self.current_layout = self.calculate_layout_type();
58    }
59
60    /// Calculate appropriate layout type based on current dimensions
61    fn calculate_layout_type(&self) -> LayoutType {
62        if self.terminal_width >= 120 {
63            LayoutType::Full
64        } else if self.terminal_width >= 80 {
65            LayoutType::Compact
66        } else {
67            LayoutType::Mobile
68        }
69    }
70
71    /// Get current layout type
72    pub fn layout_type(&self) -> LayoutType {
73        self.current_layout
74    }
75
76    /// Get current terminal width
77    pub fn width(&self) -> u16 {
78        self.terminal_width
79    }
80
81    /// Get current terminal height  
82    pub fn height(&self) -> u16 {
83        self.terminal_height
84    }
85
86    /// Check if current layout supports multiple visible panels
87    pub fn supports_multiple_panels(&self) -> bool {
88        matches!(self.current_layout, LayoutType::Full | LayoutType::Compact)
89    }
90
91    /// Get minimum width for this layout type
92    pub fn min_width_for_layout(layout: LayoutType) -> u16 {
93        match layout {
94            LayoutType::Full => 120,
95            LayoutType::Compact => 80,
96            LayoutType::Mobile => 1,
97        }
98    }
99}
100
101impl Default for LayoutManager {
102    fn default() -> Self {
103        Self::new()
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_layout_calculation() {
113        let mut manager = LayoutManager::new();
114
115        // Test full layout
116        manager.update_size(120, 30);
117        assert_eq!(manager.layout_type(), LayoutType::Full);
118
119        // Test compact layout
120        manager.update_size(100, 30);
121        assert_eq!(manager.layout_type(), LayoutType::Compact);
122
123        // Test mobile layout
124        manager.update_size(60, 20);
125        assert_eq!(manager.layout_type(), LayoutType::Mobile);
126    }
127
128    #[test]
129    fn test_multiple_panels_support() {
130        let mut manager = LayoutManager::new();
131
132        manager.update_size(120, 30);
133        assert!(manager.supports_multiple_panels());
134
135        manager.update_size(100, 30);
136        assert!(manager.supports_multiple_panels());
137
138        manager.update_size(60, 20);
139        assert!(!manager.supports_multiple_panels());
140    }
141
142    #[test]
143    fn test_min_widths() {
144        assert_eq!(LayoutManager::min_width_for_layout(LayoutType::Full), 120);
145        assert_eq!(LayoutManager::min_width_for_layout(LayoutType::Compact), 80);
146        assert_eq!(LayoutManager::min_width_for_layout(LayoutType::Mobile), 1);
147    }
148}