sql_cli/widgets/
crosshair_widget.rs1use ratatui::{
9 layout::Rect,
10 style::{Color, Modifier, Style},
11 Frame,
12};
13use tracing::{debug, trace};
14
15#[derive(Debug, Clone, Default)]
17pub struct CrosshairPosition {
18 pub row: usize,
20 pub column: usize,
22 pub visible: bool,
24}
25
26pub struct CrosshairWidget {
28 position: CrosshairPosition,
30 style: Style,
32}
33
34impl CrosshairWidget {
35 pub fn new() -> Self {
37 Self {
38 position: CrosshairPosition::default(),
39 style: Style::default()
40 .bg(Color::DarkGray)
41 .add_modifier(Modifier::REVERSED),
42 }
43 }
44
45 pub fn set_position(&mut self, row: usize, column: usize) {
47 self.position.row = row;
48 self.position.column = column;
49 self.position.visible = true;
50 debug!("Crosshair position updated to ({}, {})", row, column);
51 }
52
53 pub fn hide(&mut self) {
55 self.position.visible = false;
56 }
57
58 pub fn show(&mut self) {
60 self.position.visible = true;
61 }
62
63 pub fn position(&self) -> &CrosshairPosition {
65 &self.position
66 }
67
68 pub fn set_style(&mut self, style: Style) {
70 self.style = style;
71 }
72
73 pub fn render_overlay(
76 &self,
77 f: &mut Frame,
78 table_area: Rect,
79 viewport_row_offset: usize,
80 viewport_col_offset: usize,
81 row_heights: &[u16], col_widths: &[u16], ) {
84 if !self.position.visible {
85 return;
86 }
87
88 let visible_rows = row_heights.len();
90 let visible_cols = col_widths.len();
91
92 if self.position.row < viewport_row_offset {
94 return; }
96 let relative_row = self.position.row - viewport_row_offset;
97 if relative_row >= visible_rows {
98 return; }
100
101 if self.position.column < viewport_col_offset {
102 return; }
104 let relative_col = self.position.column - viewport_col_offset;
105 if relative_col >= visible_cols {
106 return; }
108
109 let mut y = table_area.y + 2; for i in 0..relative_row {
112 y += row_heights[i];
113 }
114
115 let mut x = table_area.x + 1; for i in 0..relative_col {
117 x += col_widths[i] + 1; }
119
120 let cell_width = col_widths[relative_col];
122 let cell_rect = Rect {
123 x,
124 y,
125 width: cell_width,
126 height: 1,
127 };
128
129 trace!(
133 "Rendering crosshair at viewport ({}, {}) -> screen ({}, {})",
134 relative_row,
135 relative_col,
136 x,
137 y
138 );
139 }
140
141 pub fn calculate_scroll_offset(
143 &self,
144 current_row_offset: usize,
145 current_col_offset: usize,
146 viewport_height: usize,
147 viewport_width: usize,
148 ) -> (usize, usize) {
149 let mut new_row_offset = current_row_offset;
150 let mut new_col_offset = current_col_offset;
151
152 if self.position.row < current_row_offset {
154 new_row_offset = self.position.row;
156 } else if self.position.row >= current_row_offset + viewport_height {
157 new_row_offset = self.position.row.saturating_sub(viewport_height / 2);
159 }
160
161 if self.position.column < current_col_offset {
163 new_col_offset = self.position.column;
165 } else if self.position.column >= current_col_offset + viewport_width {
166 new_col_offset = self.position.column.saturating_sub(viewport_width / 2);
168 }
169
170 (new_row_offset, new_col_offset)
171 }
172}