Skip to content

Commit 1c51e7d

Browse files
try to debug scrollable
1 parent ebb09e7 commit 1c51e7d

File tree

4 files changed

+159
-61
lines changed

4 files changed

+159
-61
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app.rs

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
borrow::Borrow,
23
fmt::format,
34
sync::{Arc, Mutex},
45
};
@@ -17,10 +18,14 @@ use tokio::sync::mpsc;
1718

1819
use crate::{
1920
action::Action,
20-
components::{data::Data, editor::Editor, menu::Menu, Component},
21+
components::{
22+
data::{Data, DataComponent},
23+
editor::Editor,
24+
menu::Menu,
25+
Component,
26+
},
2127
config::Config,
22-
database,
23-
database::{DbError, DbPool, Rows},
28+
database::{self, DbError, DbPool, Rows},
2429
focus::Focus,
2530
tui,
2631
};
@@ -32,23 +37,25 @@ pub struct AppState {
3237
pub table_buf_logged: bool,
3338
}
3439

35-
pub struct Components {
40+
pub struct Components<'a> {
3641
pub menu: Box<dyn Component>,
3742
pub editor: Box<dyn Component>,
38-
pub data: Box<dyn Component>,
43+
pub data: Box<dyn DataComponent<'a>>,
3944
}
4045

41-
impl Components {
42-
pub fn to_array(&mut self) -> [&mut Box<dyn Component>; 3] {
43-
[&mut self.menu, &mut self.editor, &mut self.data]
44-
}
45-
}
46+
// // TODO: see if the into_super_ref_mut fn can be fixed
47+
//
48+
// impl Components {
49+
// pub fn to_array(&mut self) -> [&mut Box<dyn Component>; 3] {
50+
// [&mut self.menu, &mut self.editor, self.data.into_super_ref_mut()]
51+
// }
52+
// }
4653

4754
pub struct App {
4855
pub config: Config,
4956
pub tick_rate: Option<f64>,
5057
pub frame_rate: Option<f64>,
51-
pub components: Components,
58+
pub components: Components<'static>,
5259
pub should_quit: bool,
5360
pub last_tick_key_events: Vec<KeyEvent>,
5461
pub state: Arc<Mutex<AppState>>,
@@ -86,17 +93,17 @@ impl App {
8693
// tui.mouse(true);
8794
tui.enter()?;
8895

89-
for component in self.components.to_array().iter_mut() {
90-
component.register_action_handler(action_tx.clone())?;
91-
}
96+
self.components.menu.register_action_handler(action_tx.clone())?;
97+
self.components.editor.register_action_handler(action_tx.clone())?;
98+
self.components.data.register_action_handler(action_tx.clone())?;
9299

93-
for component in self.components.to_array().iter_mut() {
94-
component.register_config_handler(self.config.clone())?;
95-
}
100+
self.components.menu.register_config_handler(self.config.clone())?;
101+
self.components.editor.register_config_handler(self.config.clone())?;
102+
self.components.data.register_config_handler(self.config.clone())?;
96103

97-
for component in self.components.to_array().iter_mut() {
98-
component.init(tui.size()?)?;
99-
}
104+
self.components.menu.init(tui.size()?)?;
105+
self.components.editor.init(tui.size()?)?;
106+
self.components.data.init(tui.size()?)?;
100107

101108
loop {
102109
if let Some(e) = tui.next().await {
@@ -129,10 +136,14 @@ impl App {
129136
_ => {},
130137
}
131138
if !event_consumed {
132-
for component in self.components.to_array().iter_mut() {
133-
if let Some(action) = component.handle_events(Some(e.clone()))? {
134-
action_tx.send(action)?;
135-
}
139+
if let Some(action) = self.components.menu.handle_events(Some(e.clone()))? {
140+
action_tx.send(action)?;
141+
}
142+
if let Some(action) = self.components.editor.handle_events(Some(e.clone()))? {
143+
action_tx.send(action)?;
144+
}
145+
if let Some(action) = self.components.data.handle_events(Some(e.clone()))? {
146+
action_tx.send(action)?;
136147
}
137148
}
138149
}
@@ -180,23 +191,27 @@ impl App {
180191
let mut state = self.state.lock().unwrap();
181192
match &results {
182193
Ok(rows) => {
183-
log::info!("{:?}", rows.len());
194+
log::info!("{:?} rows", rows.len());
184195
state.table_buf_logged = false;
185196
},
186197
Err(e) => {
187198
log::error!("{e:?}");
188199
},
189-
}
190-
state.data = Some(results);
200+
};
201+
self.components.data.set_data_state(Some(results));
191202
}
192203
},
193204
_ => {},
194205
}
195206
if !action_consumed {
196-
for component in self.components.to_array().iter_mut() {
197-
if let Some(action) = component.update(action.clone())? {
198-
action_tx.send(action)?
199-
};
207+
if let Some(action) = self.components.menu.update(action.clone())? {
208+
action_tx.send(action)?;
209+
}
210+
if let Some(action) = self.components.editor.update(action.clone())? {
211+
action_tx.send(action)?;
212+
}
213+
if let Some(action) = self.components.data.update(action.clone())? {
214+
action_tx.send(action)?;
200215
}
201216
}
202217
}

src/components/data.rs

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,86 @@ use ratatui::{prelude::*, widgets::*};
1010
use serde::{Deserialize, Serialize};
1111
use tokio::sync::mpsc::UnboundedSender;
1212

13-
use super::{Component, Frame};
13+
use super::Frame;
1414
use crate::{
1515
action::Action,
1616
app::{App, AppState},
17-
components::scrollable::{ScrollDirection, Scrollable},
17+
components::{
18+
scrollable::{ScrollDirection, Scrollable},
19+
Component,
20+
},
1821
config::{Config, KeyBindings},
1922
database::{get_headers, parse_value, row_to_json, row_to_vec, DbError, Rows},
2023
focus::Focus,
2124
tui::Event,
2225
};
2326

27+
pub enum DataState {
28+
NoResults,
29+
Blank,
30+
HasResults,
31+
Error(DbError),
32+
}
33+
34+
pub trait SettableDataTable<'a> {
35+
fn set_data_state(&mut self, data: Option<Result<Rows, DbError>>);
36+
}
37+
38+
pub trait DataComponent<'a>: Component + SettableDataTable<'a> {}
39+
impl<'a, T> DataComponent<'a> for T where T: Component + SettableDataTable<'a>
40+
{
41+
}
42+
2443
pub struct Data<'a> {
2544
command_tx: Option<UnboundedSender<Action>>,
2645
config: Config,
2746
scrollable: Scrollable<'a>,
47+
data_state: DataState,
2848
state: Arc<Mutex<AppState>>,
2949
}
3050

3151
impl<'a> Data<'a> {
3252
pub fn new(state: Arc<Mutex<AppState>>) -> Self {
33-
Data { command_tx: None, config: Config::default(), scrollable: Scrollable::default(), state }
53+
Data {
54+
command_tx: None,
55+
config: Config::default(),
56+
scrollable: Scrollable::default(),
57+
data_state: DataState::Blank,
58+
state,
59+
}
3460
}
61+
}
3562

36-
pub fn set_data() {
37-
// TODO
63+
impl<'a> SettableDataTable<'a> for Data<'a> {
64+
fn set_data_state(&mut self, data: Option<Result<Rows, DbError>>) {
65+
match data {
66+
Some(Ok(rows)) => {
67+
if rows.is_empty() {
68+
self.data_state = DataState::NoResults;
69+
} else {
70+
let headers = get_headers(&rows);
71+
let header_row =
72+
Row::new(headers.iter().map(|h| Cell::from(format!("{}\n{}", h.name, h.type_name))).collect::<Vec<Cell>>())
73+
.height(2)
74+
.bottom_margin(1);
75+
let value_rows = rows.iter().map(|r| Row::new(row_to_vec(r)).bottom_margin(1)).collect::<Vec<Row>>();
76+
let buf_table =
77+
Table::default().rows(value_rows).header(header_row).style(Style::default()).column_spacing(1);
78+
self.scrollable.child(
79+
Box::new(buf_table),
80+
16_u16.saturating_mul(headers.len() as u16),
81+
4_u16.saturating_mul(rows.len() as u16),
82+
);
83+
self.data_state = DataState::HasResults;
84+
}
85+
},
86+
Some(Err(e)) => {
87+
self.data_state = DataState::Error(e);
88+
},
89+
_ => {
90+
self.data_state = DataState::Blank;
91+
},
92+
}
3893
}
3994
}
4095

@@ -94,34 +149,58 @@ impl<'a> Component for Data<'a> {
94149
Style::new().dim()
95150
});
96151

97-
match &state.data {
98-
Some(Ok(rows)) => 'rows: {
99-
if rows.is_empty() {
100-
f.render_widget(Paragraph::new("no results").wrap(Wrap { trim: false }).block(block), area);
101-
break 'rows;
102-
}
103-
let headers = get_headers(rows);
104-
let header_row =
105-
Row::new(headers.iter().map(|h| Cell::from(format!("{}\n{}", h.name, h.type_name))).collect::<Vec<Cell>>())
106-
.height(2)
107-
.bottom_margin(1);
108-
let value_rows = rows.iter().map(|r| Row::new(row_to_vec(r)).bottom_margin(1)).collect::<Vec<Row>>();
109-
let buf_table = Table::default().rows(value_rows).header(header_row).style(Style::default()).column_spacing(1);
110-
self.scrollable.child(Box::new(buf_table), 100, 250).block(block);
111-
152+
match &self.data_state {
153+
DataState::NoResults => {
154+
f.render_widget(Paragraph::new("no results").wrap(Wrap { trim: false }).block(block), area);
155+
},
156+
DataState::Blank => {
157+
f.render_widget(Paragraph::new("").wrap(Wrap { trim: false }).block(block), area);
158+
},
159+
DataState::HasResults => {
112160
if !state.table_buf_logged {
113161
self.scrollable.log();
114162
state.table_buf_logged = true;
115163
}
116-
117-
self.scrollable.draw(f, area).unwrap();
164+
self.scrollable.block(block);
165+
self.scrollable.draw(f, area)?;
118166
},
119-
Some(Err(e)) => {
120-
f.render_widget(Paragraph::new(format!("{:?}", e.to_string())).wrap(Wrap { trim: false }).block(block), area)
167+
DataState::Error(e) => {
168+
f.render_widget(Paragraph::new(format!("{:?}", e.to_string())).wrap(Wrap { trim: false }).block(block), area);
121169
},
122-
_ => f.render_widget(Paragraph::new("").wrap(Wrap { trim: false }).block(block), area),
123170
}
124171

125172
Ok(())
126173
}
127174
}
175+
176+
// // TODO: see if this trait can be fixed and used
177+
//
178+
// // based on: https://users.rust-lang.org/t/casting-traitobject-to-super-trait/33524/9
179+
// pub trait IntoComponent<'a, Super: ?Sized> {
180+
// fn as_super(&self) -> &Super;
181+
// fn as_super_mut(&mut self) -> &mut Super;
182+
// fn into_super(self: Box<Self>) -> Box<Super>;
183+
// fn into_super_ref_mut(self: &'a mut Box<Self>) -> &'a mut Box<Super>;
184+
// }
185+
//
186+
// impl<'a, T: 'a + Component> IntoComponent<'a, dyn Component + 'a> for T
187+
// where
188+
// T: Component + 'a,
189+
// {
190+
// fn as_super(&self) -> &(dyn Component + 'a) {
191+
// self
192+
// }
193+
//
194+
// fn as_super_mut(&mut self) -> &mut (dyn Component + 'a) {
195+
// self
196+
// }
197+
//
198+
// fn into_super(self: Box<Self>) -> Box<dyn Component + 'a> {
199+
// self
200+
// }
201+
//
202+
// fn into_super_ref_mut(self: &'a mut Box<Self>) -> &'a mut Box<dyn Component + 'a> {
203+
// self
204+
// }
205+
// }
206+
//

src/components/scrollable.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ impl<'a> Scrollable<'a> {
3737
}
3838
}
3939

40-
pub fn child(&mut self, child_widget: Box<dyn WidgetRef>, max_height: u16, max_width: u16) -> &mut Self {
40+
pub fn child(&mut self, child_widget: Box<dyn WidgetRef>, max_width: u16, max_height: u16) -> &mut Self {
4141
let mut buf = Buffer::empty(Rect::new(0, 0, max_width, max_height));
4242
child_widget.render_ref(buf.area, &mut buf);
4343
let child_buffer = clamp(buf);
44+
log::info!("child buffer: {:?}", child_buffer.area);
4445
self.child_buffer = child_buffer;
4546
self
4647
}
@@ -73,6 +74,7 @@ impl<'a> Scrollable<'a> {
7374
}
7475

7576
pub fn log(&self) {
77+
log::info!("logging");
7678
let buf_height = self.child_buffer.area.height;
7779
let buf_width = self.child_buffer.area.width;
7880
for n in 0..buf_height {
@@ -180,19 +182,21 @@ fn get_max_offsets(child_buffer: &Buffer, parent_area: &Rect, parent_block: &Opt
180182
fn clamp(buf: Buffer) -> Buffer {
181183
let height = buf.area.height;
182184
let width = buf.area.width;
185+
log::info!("height, width: {} {}", height, width);
183186
let mut used_height: u16 = 0;
184187
let mut used_width: u16 = 0;
185188
for y in (0..height).rev() {
186189
let row = get_row(&buf.content, y, width);
187190
for x in (0..width).rev() {
188191
let cell = &row[x as usize];
189192
if cell.symbol() != " " {
190-
used_height = std::cmp::max(used_height, y + 1);
191-
used_width = std::cmp::max(used_width, x + 1);
193+
used_height = std::cmp::max(used_height, y.saturating_add(1));
194+
used_width = std::cmp::max(used_width, x.saturating_add(1));
192195
}
193196
}
194197
}
195198
let mut content: Vec<ratatui::buffer::Cell> = Vec::new();
199+
log::info!("used height, width: {} {}", used_height, used_width);
196200
for y in 0..used_height {
197201
let row = get_row(&buf.content, y, width);
198202
for x in 0..used_width {

0 commit comments

Comments
 (0)