1use crate::action::PanelType;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum LayoutMode {
5 Horizontal,
6 Vertical,
7}
8
9#[derive(Debug, Clone)]
11pub struct HistoryConfig {
12 pub enabled: bool,
14 pub max_entries: usize,
16}
17
18impl Default for HistoryConfig {
19 fn default() -> Self {
20 Self {
21 enabled: true,
22 max_entries: 5000,
23 }
24 }
25}
26
27#[derive(Debug, Clone)]
29pub struct UiConfig {
30 pub layout_mode: LayoutMode,
31 pub panel_ratios: [u16; 3], pub show_source_panel: bool,
33 pub two_panel_ratios: [u16; 2], pub default_focus: crate::action::PanelType,
35 pub history: HistoryConfig,
36 pub ebpf_max_messages: usize,
37}
38
39#[derive(Debug)]
41pub struct UIState {
42 pub layout: LayoutState,
43 pub focus: FocusState,
44 pub config: UiConfig,
45}
46
47impl UIState {
48 pub fn new(ui_config: UiConfig) -> Self {
49 let effective_default = if !ui_config.show_source_panel
51 && matches!(ui_config.default_focus, PanelType::Source)
52 {
53 PanelType::InteractiveCommand
54 } else {
55 ui_config.default_focus
56 };
57
58 Self {
59 layout: LayoutState::new(ui_config.layout_mode),
60 focus: FocusState::new_with_default(effective_default),
61 config: ui_config,
62 }
63 }
64
65 pub fn new_with_layout_mode(layout_mode: LayoutMode) -> Self {
67 Self::new(UiConfig {
68 layout_mode,
69 panel_ratios: [4, 3, 3], show_source_panel: true,
71 two_panel_ratios: [3, 3],
72 default_focus: crate::action::PanelType::InteractiveCommand,
73 history: HistoryConfig::default(),
74 ebpf_max_messages: 2000, })
76 }
77}
78
79#[derive(Debug)]
80pub struct LayoutState {
81 pub mode: LayoutMode,
82 pub is_fullscreen: bool,
83}
84
85impl LayoutState {
86 pub fn new(mode: LayoutMode) -> Self {
87 Self {
88 mode,
89 is_fullscreen: false,
90 }
91 }
92
93 pub fn toggle_fullscreen(&mut self) {
94 self.is_fullscreen = !self.is_fullscreen;
95 }
96
97 pub fn switch_mode(&mut self) {
98 self.mode = match self.mode {
99 LayoutMode::Horizontal => LayoutMode::Vertical,
100 LayoutMode::Vertical => LayoutMode::Horizontal,
101 };
102 }
103}
104
105#[derive(Debug)]
106pub struct FocusState {
107 pub current_panel: PanelType,
108 pub expecting_window_nav: bool,
109}
110
111impl FocusState {
112 pub fn new() -> Self {
113 Self {
114 current_panel: PanelType::InteractiveCommand,
115 expecting_window_nav: false,
116 }
117 }
118
119 pub fn new_with_default(default_panel: PanelType) -> Self {
120 Self {
121 current_panel: default_panel,
122 expecting_window_nav: false,
123 }
124 }
125
126 pub fn cycle_next(&mut self, source_enabled: bool) {
127 self.current_panel = match (self.current_panel, source_enabled) {
128 (PanelType::Source, _) => PanelType::EbpfInfo,
129 (PanelType::EbpfInfo, _) => PanelType::InteractiveCommand,
130 (PanelType::InteractiveCommand, true) => PanelType::Source,
131 (PanelType::InteractiveCommand, false) => PanelType::EbpfInfo,
132 };
133 }
134
135 pub fn cycle_previous(&mut self, source_enabled: bool) {
136 self.current_panel = match (self.current_panel, source_enabled) {
137 (PanelType::Source, _) => PanelType::InteractiveCommand,
138 (PanelType::EbpfInfo, true) => PanelType::Source,
139 (PanelType::EbpfInfo, false) => PanelType::InteractiveCommand,
140 (PanelType::InteractiveCommand, _) => PanelType::EbpfInfo,
141 };
142 }
143
144 pub fn set_panel(&mut self, panel: PanelType) {
145 self.current_panel = panel;
146 }
147
148 pub fn is_focused(&self, panel: PanelType) -> bool {
149 self.current_panel == panel
150 }
151
152 pub fn move_focus_in_direction(
153 &mut self,
154 direction: crate::action::WindowDirection,
155 layout_mode: LayoutMode,
156 source_enabled: bool,
157 ) {
158 use crate::action::WindowDirection;
159
160 match layout_mode {
161 LayoutMode::Horizontal => {
162 match direction {
163 WindowDirection::Left => {
164 self.current_panel = match (self.current_panel, source_enabled) {
166 (PanelType::InteractiveCommand, _) => PanelType::EbpfInfo,
167 (PanelType::EbpfInfo, true) => PanelType::Source,
168 (PanelType::EbpfInfo, false) => PanelType::InteractiveCommand,
169 (PanelType::Source, _) => PanelType::InteractiveCommand, };
171 }
172 WindowDirection::Right => {
173 self.current_panel = match (self.current_panel, source_enabled) {
175 (PanelType::Source, _) => PanelType::EbpfInfo,
176 (PanelType::EbpfInfo, _) => PanelType::InteractiveCommand,
177 (PanelType::InteractiveCommand, true) => PanelType::Source, (PanelType::InteractiveCommand, false) => PanelType::EbpfInfo,
179 };
180 }
181 _ => {} }
183 }
184 LayoutMode::Vertical => {
185 match direction {
186 WindowDirection::Up => {
187 self.current_panel = match (self.current_panel, source_enabled) {
188 (PanelType::InteractiveCommand, _) => PanelType::EbpfInfo,
189 (PanelType::EbpfInfo, true) => PanelType::Source,
190 (PanelType::EbpfInfo, false) => PanelType::InteractiveCommand,
191 (PanelType::Source, _) => PanelType::InteractiveCommand, };
193 }
194 WindowDirection::Down => {
195 self.current_panel = match (self.current_panel, source_enabled) {
196 (PanelType::Source, _) => PanelType::EbpfInfo,
197 (PanelType::EbpfInfo, _) => PanelType::InteractiveCommand,
198 (PanelType::InteractiveCommand, true) => PanelType::Source, (PanelType::InteractiveCommand, false) => PanelType::EbpfInfo,
200 };
201 }
202 _ => {} }
204 }
205 }
206 }
207}
208
209impl Default for FocusState {
210 fn default() -> Self {
211 Self::new()
212 }
213}