broken scrolling
This commit is contained in:
@@ -12,7 +12,7 @@ use ratatui::{
|
|||||||
use crate::app::{
|
use crate::app::{
|
||||||
calc::{Grid, LEN},
|
calc::{Grid, LEN},
|
||||||
error_msg::ErrorMessage,
|
error_msg::ErrorMessage,
|
||||||
mode::{Chord, Mode},
|
mode::{Chord, Mode}, screen::ScreenSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@@ -22,28 +22,13 @@ pub struct App {
|
|||||||
pub file: Option<PathBuf>,
|
pub file: Option<PathBuf>,
|
||||||
pub error_msg: ErrorMessage,
|
pub error_msg: ErrorMessage,
|
||||||
pub vars: HashMap<String, String>,
|
pub vars: HashMap<String, String>,
|
||||||
|
pub screen: ScreenSpace,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for &App {
|
impl Widget for &App {
|
||||||
fn render(self, area: prelude::Rect, buf: &mut prelude::Buffer) {
|
fn render(self, area: prelude::Rect, buf: &mut prelude::Buffer) {
|
||||||
let len = LEN as u16;
|
|
||||||
|
|
||||||
let mut cell_height = 1;
|
let (x_max, y_max) = self.screen.how_many_cells_fit_in(&area, &self.vars);
|
||||||
let mut cell_length = 10;
|
|
||||||
|
|
||||||
if let Some(h) = self.vars.get("height") {
|
|
||||||
if let Ok(p) = h.parse::<u16>() {
|
|
||||||
cell_height = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(l) = self.vars.get("length") {
|
|
||||||
if let Ok(p) = l.parse::<u16>() {
|
|
||||||
cell_length = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let x_max = if area.width / cell_length > len { len - 1 } else { area.width / cell_length };
|
|
||||||
let y_max = if area.height / cell_height > len { len - 1 } else { area.height / cell_height };
|
|
||||||
|
|
||||||
let is_selected = |x: usize, y: usize| -> bool {
|
let is_selected = |x: usize, y: usize| -> bool {
|
||||||
if let Mode::Visual((mut x1, mut y1)) = self.mode {
|
if let Mode::Visual((mut x1, mut y1)) = self.mode {
|
||||||
@@ -74,11 +59,11 @@ impl Widget for &App {
|
|||||||
// to index the grid, these are you values.
|
// to index the grid, these are you values.
|
||||||
let mut x_idx: usize = 0;
|
let mut x_idx: usize = 0;
|
||||||
let mut y_idx: usize = 0;
|
let mut y_idx: usize = 0;
|
||||||
if y != 0 {
|
|
||||||
y_idx = y as usize - 1;
|
|
||||||
}
|
|
||||||
if x != 0 {
|
if x != 0 {
|
||||||
x_idx = x as usize - 1;
|
x_idx = x as usize - 1 + self.screen.scroll_x();
|
||||||
|
}
|
||||||
|
if y != 0 {
|
||||||
|
y_idx = y as usize - 1 + self.screen.y();
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_selected(x.into(), y.into()) {
|
if is_selected(x.into(), y.into()) {
|
||||||
@@ -136,8 +121,10 @@ impl Widget for &App {
|
|||||||
} else {
|
} else {
|
||||||
// the formula is broken
|
// the formula is broken
|
||||||
display = e.to_owned();
|
display = e.to_owned();
|
||||||
style =
|
style = Style::new()
|
||||||
Style::new().fg(Color::Red).underline_color(Color::Red).add_modifier(Modifier::UNDERLINED)
|
.fg(Color::Red)
|
||||||
|
.underline_color(Color::Red)
|
||||||
|
.add_modifier(Modifier::UNDERLINED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,8 +138,14 @@ impl Widget for &App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let w = self.screen.get_cell_width(&self.vars) as u16;
|
||||||
let area = Rect::new(area.x + (x * cell_length), area.y + (y * cell_height), cell_length, cell_height);
|
let h = self.screen.get_cell_height(&self.vars) as u16;
|
||||||
|
let area = Rect::new(
|
||||||
|
area.x + (x * w),
|
||||||
|
area.y + (y * h),
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
);
|
||||||
|
|
||||||
Paragraph::new(display).style(style).render(area, buf);
|
Paragraph::new(display).style(style).render(area, buf);
|
||||||
}
|
}
|
||||||
@@ -169,6 +162,7 @@ impl App {
|
|||||||
file: None,
|
file: None,
|
||||||
error_msg: ErrorMessage::none(),
|
error_msg: ErrorMessage::none(),
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
|
screen: ScreenSpace::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,9 +212,22 @@ impl App {
|
|||||||
|
|
||||||
frame.render_widget(self, body);
|
frame.render_widget(self, body);
|
||||||
frame.render_widget(&self.error_msg, cmd_line_right);
|
frame.render_widget(&self.error_msg, cmd_line_right);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
frame.render_widget(Paragraph::new(format!("x/w y/h: cursor{:?} scroll({}, {}) cell({}, {}) screen({}, {})",
|
||||||
|
self.grid.selected_cell,
|
||||||
|
self.screen.scroll_x(),
|
||||||
|
self.screen.y(),
|
||||||
|
self.screen.get_cell_width(&self.vars),
|
||||||
|
self.screen.get_cell_height(&self.vars),
|
||||||
|
body.width,
|
||||||
|
body.height,
|
||||||
|
)), cmd_line_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_events(&mut self) -> io::Result<()> {
|
fn handle_events(&mut self) -> io::Result<()> {
|
||||||
|
// make sure cursor is inside window
|
||||||
|
self.screen.scroll_based_on_cursor_location(self.grid.selected_cell, &self.vars);
|
||||||
|
|
||||||
match &mut self.mode {
|
match &mut self.mode {
|
||||||
Mode::Chord(chord) => match event::read()? {
|
Mode::Chord(chord) => match event::read()? {
|
||||||
event::Event::Key(key) => match key.code {
|
event::Event::Key(key) => match key.code {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use evalexpr::*;
|
|||||||
|
|
||||||
use crate::app::ctx;
|
use crate::app::ctx;
|
||||||
|
|
||||||
pub const LEN: usize = 100;
|
pub const LEN: usize = 1000;
|
||||||
|
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
// a b c ...
|
// a b c ...
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ mod calc;
|
|||||||
mod mode;
|
mod mode;
|
||||||
mod error_msg;
|
mod error_msg;
|
||||||
mod ctx;
|
mod ctx;
|
||||||
|
mod screen;
|
||||||
@@ -4,9 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
prelude,
|
layout::Rect, prelude, style::{Color, Style}, widgets::{Paragraph, Widget}
|
||||||
style::{Color, Style},
|
|
||||||
widgets::{Paragraph, Widget},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::app::{app::App, calc::LEN, error_msg::ErrorMessage};
|
use crate::app::{app::App, calc::LEN, error_msg::ErrorMessage};
|
||||||
|
|||||||
80
src/app/screen.rs
Normal file
80
src/app/screen.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
use std::{collections::HashMap, sync::RwLock};
|
||||||
|
|
||||||
|
use ratatui::{layout::Rect, prelude};
|
||||||
|
|
||||||
|
use crate::app::calc::LEN;
|
||||||
|
|
||||||
|
pub struct ScreenSpace {
|
||||||
|
/// This is measured in cells
|
||||||
|
scroll: (usize, usize),
|
||||||
|
default_cell_len: usize,
|
||||||
|
default_cell_hight: usize,
|
||||||
|
/// This is measured in chars
|
||||||
|
last_seen_screen_size: RwLock<(usize, usize)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScreenSpace {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
scroll: (0, 0),
|
||||||
|
default_cell_len: 10,
|
||||||
|
default_cell_hight: 1,
|
||||||
|
last_seen_screen_size: RwLock::new((0,0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_based_on_cursor_location(&mut self, (cursor_x, cursor_y): (usize, usize), vars: &HashMap<String, String>) {
|
||||||
|
if let Ok(screen_size) = self.last_seen_screen_size.read() {
|
||||||
|
|
||||||
|
// screen seems to be 2 cells smaller than it should be
|
||||||
|
let x_cells = (screen_size.0 / self.get_cell_width(vars) as usize)-2;
|
||||||
|
|
||||||
|
let lower_x = self.scroll_x();
|
||||||
|
let upper_x = self.scroll_x() + x_cells;
|
||||||
|
|
||||||
|
if cursor_x<=lower_x {
|
||||||
|
self.scroll.0 = self.scroll.0.saturating_sub(1);
|
||||||
|
}
|
||||||
|
if cursor_x > upper_x {
|
||||||
|
self.scroll.0 = self.scroll.0.saturating_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_x(&self) -> usize {
|
||||||
|
self.scroll.0
|
||||||
|
}
|
||||||
|
pub fn y(&self) -> usize{
|
||||||
|
self.scroll.1
|
||||||
|
}
|
||||||
|
pub fn get_cell_height(&self, vars: &HashMap<String, String>) -> usize {
|
||||||
|
if let Some(h) = vars.get("height") {
|
||||||
|
if let Ok(p) = h.parse::<usize>() {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.default_cell_hight
|
||||||
|
}
|
||||||
|
pub fn get_cell_width(&self, vars: &HashMap<String, String>) -> usize {
|
||||||
|
if let Some(h) = vars.get("length") {
|
||||||
|
if let Ok(p) = h.parse::<usize>() {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.default_cell_len
|
||||||
|
}
|
||||||
|
pub fn how_many_cells_fit_in(&self, area: &prelude::Rect, vars: &HashMap<String, String>) -> (u16, u16) {
|
||||||
|
if let Ok(mut l) = self.last_seen_screen_size.write() {
|
||||||
|
l.0 = area.width as usize;
|
||||||
|
l.1 = area.height as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x_max =
|
||||||
|
if area.width as usize / self.get_cell_width(vars) > LEN { LEN - 1 } else { area.width as usize / self.get_cell_width(vars)};
|
||||||
|
let y_max =
|
||||||
|
if area.height as usize / self.get_cell_height(vars) > LEN { LEN - 1 } else { area.height as usize / self.get_cell_height(vars)};
|
||||||
|
(x_max as u16, y_max as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user