ui: CellBuffer cleanups

- Remove unused Traits etc
- Make scrolling a method
jmap
Manos Pitsidianakis 2019-11-24 20:42:26 +02:00
parent e5f5febd6b
commit 1df7a35f0f
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 195 additions and 201 deletions

View File

@ -33,67 +33,18 @@ use std::fmt;
use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::ops::{Deref, DerefMut, Index, IndexMut};
use termion::color::{AnsiValue, Rgb as TermionRgb}; use termion::color::{AnsiValue, Rgb as TermionRgb};
/// Types and implementations taken from rustty for convenience. /// In a scroll region up and down cursor movements shift the region vertically. The new lines are
/// empty.
pub trait CellAccessor: HasSize { #[derive(Debug, Clone, PartialEq, Eq, Default)]
fn cellvec(&self) -> &Vec<Cell>; pub struct ScrollRegion {
fn cellvec_mut(&mut self) -> &mut Vec<Cell>; pub top: usize,
pub bottom: usize,
/// Clears `self`, using the given `Cell` as a blank. pub left: usize,
fn clear(&mut self, blank: Cell) { pub right: usize,
for cell in self.cellvec_mut().iter_mut() {
*cell = blank;
}
}
fn pos_to_index(&self, x: usize, y: usize) -> Option<usize> {
let (cols, rows) = self.size();
if x < cols && y < rows {
Some((cols * y) + x)
} else {
None
}
}
/// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of
/// bounds.
///
/// # Examples
///
/// ```norun
/// use rustty::{Terminal, CellAccessor};
///
/// let mut term = Terminal::new().unwrap();
///
/// let a_cell = term.get(5, 5);
/// ```
fn get(&self, x: usize, y: usize) -> Option<&Cell> {
match self.pos_to_index(x, y) {
Some(i) => self.cellvec().get(i),
None => None,
}
}
/// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index
/// is out of bounds.
///
/// # Examples
///
/// ```norun
/// use rustty::{Terminal, CellAccessor};
///
/// let mut term = Terminal::new().unwrap();
///
/// let a_mut_cell = term.get_mut(5, 5);
/// ```
fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> {
match self.pos_to_index(x, y) {
Some(i) => self.cellvec_mut().get_mut(i),
None => None,
}
}
} }
/// Types and implementations taken from rustty for convenience.
/// An array of `Cell`s that represents a terminal display. /// An array of `Cell`s that represents a terminal display.
/// ///
/// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices correspond to a /// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices correspond to a
@ -216,22 +167,189 @@ impl CellBuffer {
self.cols = 0; self.cols = 0;
self.rows = 0; self.rows = 0;
} }
}
impl HasSize for CellBuffer { /// Clears `self`, using the given `Cell` as a blank.
fn size(&self) -> Size { pub fn clear(&mut self, blank: Cell) {
for cell in self.cellvec_mut().iter_mut() {
*cell = blank;
}
}
pub fn pos_to_index(&self, x: usize, y: usize) -> Option<usize> {
let (cols, rows) = self.size();
if x < cols && y < rows {
Some((cols * y) + x)
} else {
None
}
}
/// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of
/// bounds.
///
/// # Examples
///
/// ```norun
/// use rustty::{Terminal, CellAccessor};
///
/// let mut term = Terminal::new().unwrap();
///
/// let a_cell = term.get(5, 5);
/// ```
pub fn get(&self, x: usize, y: usize) -> Option<&Cell> {
match self.pos_to_index(x, y) {
Some(i) => self.cellvec().get(i),
None => None,
}
}
/// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index
/// is out of bounds.
///
/// # Examples
///
/// ```norun
/// use rustty::{Terminal, CellAccessor};
///
/// let mut term = Terminal::new().unwrap();
///
/// let a_mut_cell = term.get_mut(5, 5);
/// ```
pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> {
match self.pos_to_index(x, y) {
Some(i) => self.cellvec_mut().get_mut(i),
None => None,
}
}
pub fn size(&self) -> (usize, usize) {
(self.cols, self.rows) (self.cols, self.rows)
} }
}
impl CellAccessor for CellBuffer { pub fn cellvec(&self) -> &Vec<Cell> {
fn cellvec(&self) -> &Vec<Cell> {
&self.buf &self.buf
} }
fn cellvec_mut(&mut self) -> &mut Vec<Cell> { pub fn cellvec_mut(&mut self) -> &mut Vec<Cell> {
&mut self.buf &mut self.buf
} }
pub fn cols(&self) -> usize {
self.size().0
}
pub fn rows(&self) -> usize {
self.size().1
}
#[inline(always)]
/// Performs the normal scroll up motion:
///
/// First clear offset number of lines:
///
/// For offset = 1, top = 1:
///
/// | 111111111111 | | |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | 666666666666 |
///
/// In each step, swap the current line with the next by offset:
///
/// | | | 222222222222 |
/// | 222222222222 | | |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | 666666666666 |
///
/// Result:
/// Before After
/// | 111111111111 | | 222222222222 |
/// | 222222222222 | | 333333333333 |
/// | 333333333333 | | 444444444444 |
/// | 444444444444 | | 555555555555 |
/// | 555555555555 | | 666666666666 |
/// | 666666666666 | | |
///
pub fn scroll_up(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) {
//debug!(
// "scroll_up scroll_region {:?}, top: {} offset {}",
// scroll_region, top, offset
//);
let l = scroll_region.left;
let r = if scroll_region.right == 0 {
self.size().0
} else {
scroll_region.right
};
for y in top..=(top + offset - 1) {
for x in l..r {
self[(x, y)] = Cell::default();
}
}
for y in top..=(scroll_region.bottom - offset) {
for x in l..r {
let temp = self[(x, y)];
self[(x, y)] = self[(x, y + offset)];
self[(x, y + offset)] = temp;
}
}
}
#[inline(always)]
/// Performs the normal scroll down motion:
///
/// First clear offset number of lines:
///
/// For offset = 1, top = 1:
///
/// | 111111111111 | | 111111111111 |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | |
///
/// In each step, swap the current line with the prev by offset:
///
/// | 111111111111 | | 111111111111 |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | |
/// | | | 555555555555 |
///
/// Result:
/// Before After
/// | 111111111111 | | |
/// | 222222222222 | | 111111111111 |
/// | 333333333333 | | 222222222222 |
/// | 444444444444 | | 333333333333 |
/// | 555555555555 | | 444444444444 |
/// | 666666666666 | | 555555555555 |
///
pub fn scroll_down(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) {
//debug!(
// "scroll_down scroll_region {:?}, top: {} offset {}",
// scroll_region, top, offset
//);
for y in (scroll_region.bottom - offset + 1)..=scroll_region.bottom {
for x in 0..self.size().0 {
self[(x, y)] = Cell::default();
}
}
for y in ((top + offset)..=scroll_region.bottom).rev() {
for x in 0..self.size().0 {
let temp = self[(x, y)];
self[(x, y)] = self[(x, y - offset)];
self[(x, y - offset)] = temp;
}
}
}
} }
impl Deref for CellBuffer { impl Deref for CellBuffer {

View File

@ -14,14 +14,6 @@ use text_processing::wcwidth;
* The main process copies the grid whenever the actual terminal is redrawn. * The main process copies the grid whenever the actual terminal is redrawn.
**/ **/
/// In a scroll region up and down cursor movements shift the region vertically. The new lines are
/// empty.
#[derive(Debug)]
struct ScrollRegion {
top: usize,
bottom: usize,
}
#[derive(Debug)] #[derive(Debug)]
pub struct EmbedGrid { pub struct EmbedGrid {
cursor: (usize, usize), cursor: (usize, usize),
@ -63,7 +55,12 @@ impl EmbedGrid {
pub fn new(stdin: std::fs::File, child_pid: nix::unistd::Pid) -> Self { pub fn new(stdin: std::fs::File, child_pid: nix::unistd::Pid) -> Self {
EmbedGrid { EmbedGrid {
cursor: (0, 0), cursor: (0, 0),
scroll_region: ScrollRegion { top: 0, bottom: 0 }, scroll_region: ScrollRegion {
top: 0,
bottom: 0,
left: 0,
..Default::default()
},
terminal_size: (0, 0), terminal_size: (0, 0),
grid: CellBuffer::default(), grid: CellBuffer::default(),
state: State::Normal, state: State::Normal,
@ -191,7 +188,7 @@ impl EmbedGrid {
// ESCD Linefeed // ESCD Linefeed
debug!("{}", EscCode::from((&(*state), byte))); debug!("{}", EscCode::from((&(*state), byte)));
if cursor.1 == scroll_region.bottom { if cursor.1 == scroll_region.bottom {
scroll_up(grid, scroll_region, scroll_region.top, 1); grid.scroll_up(scroll_region, scroll_region.top, 1);
} else { } else {
cursor.1 += 1; cursor.1 += 1;
} }
@ -253,7 +250,7 @@ impl EmbedGrid {
if cursor.1 + 1 < terminal_size.1 { if cursor.1 + 1 < terminal_size.1 {
if cursor.1 == scroll_region.bottom { if cursor.1 == scroll_region.bottom {
scroll_up(grid, scroll_region, cursor.1, 1); grid.scroll_up(scroll_region, cursor.1, 1);
} else { } else {
cursor.1 += 1; cursor.1 += 1;
} }
@ -335,7 +332,7 @@ impl EmbedGrid {
if *auto_wrap_mode && *wrap_next { if *auto_wrap_mode && *wrap_next {
*wrap_next = false; *wrap_next = false;
if cursor.1 == scroll_region.bottom { if cursor.1 == scroll_region.bottom {
scroll_up(grid, scroll_region, scroll_region.top, 1); grid.scroll_up(scroll_region, scroll_region.top, 1);
} else { } else {
cursor.1 += 1; cursor.1 += 1;
} }
@ -488,7 +485,7 @@ impl EmbedGrid {
1 1
}; };
scroll_down(grid, scroll_region, cursor.1, n); grid.scroll_down(scroll_region, cursor.1, n);
debug!("{}", EscCode::from((&(*state), byte))); debug!("{}", EscCode::from((&(*state), byte)));
*state = State::Normal; *state = State::Normal;
@ -503,7 +500,7 @@ impl EmbedGrid {
1 1
}; };
scroll_up(grid, scroll_region, cursor.1, n); grid.scroll_up(scroll_region, cursor.1, n);
debug!("{}", EscCode::from((&(*state), byte))); debug!("{}", EscCode::from((&(*state), byte)));
*state = State::Normal; *state = State::Normal;
@ -1106,106 +1103,3 @@ impl EmbedGrid {
} }
} }
} }
#[inline(always)]
/// Performs the normal scroll up motion:
///
/// First clear offset number of lines:
///
/// For offset = 1, top = 1:
///
/// | 111111111111 | | |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | 666666666666 |
///
/// In each step, swap the current line with the next by offset:
///
/// | | | 222222222222 |
/// | 222222222222 | | |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | 666666666666 |
///
/// Result:
/// Before After
/// | 111111111111 | | 222222222222 |
/// | 222222222222 | | 333333333333 |
/// | 333333333333 | | 444444444444 |
/// | 444444444444 | | 555555555555 |
/// | 555555555555 | | 666666666666 |
/// | 666666666666 | | |
///
fn scroll_up(grid: &mut CellBuffer, scroll_region: &ScrollRegion, top: usize, offset: usize) {
//debug!(
// "scroll_up scroll_region {:?}, top: {} offset {}",
// scroll_region, top, offset
//);
for y in top..=(top + offset - 1) {
for x in 0..grid.size().0 {
grid[(x, y)] = Cell::default();
}
}
for y in top..=(scroll_region.bottom - offset) {
for x in 0..grid.size().0 {
let temp = grid[(x, y)];
grid[(x, y)] = grid[(x, y + offset)];
grid[(x, y + offset)] = temp;
}
}
}
#[inline(always)]
/// Performs the normal scroll down motion:
///
/// First clear offset number of lines:
///
/// For offset = 1, top = 1:
///
/// | 111111111111 | | 111111111111 |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | 555555555555 |
/// | 666666666666 | | |
///
/// In each step, swap the current line with the prev by offset:
///
/// | 111111111111 | | 111111111111 |
/// | 222222222222 | | 222222222222 |
/// | 333333333333 | | 333333333333 |
/// | 444444444444 | --> | 444444444444 |
/// | 555555555555 | | |
/// | | | 555555555555 |
///
/// Result:
/// Before After
/// | 111111111111 | | |
/// | 222222222222 | | 111111111111 |
/// | 333333333333 | | 222222222222 |
/// | 444444444444 | | 333333333333 |
/// | 555555555555 | | 444444444444 |
/// | 666666666666 | | 555555555555 |
///
fn scroll_down(grid: &mut CellBuffer, scroll_region: &ScrollRegion, top: usize, offset: usize) {
//debug!(
// "scroll_down scroll_region {:?}, top: {} offset {}",
// scroll_region, top, offset
//);
for y in (scroll_region.bottom - offset + 1)..=scroll_region.bottom {
for x in 0..grid.size().0 {
grid[(x, y)] = Cell::default();
}
}
for y in ((top + offset)..=scroll_region.bottom).rev() {
for x in 0..grid.size().0 {
let temp = grid[(x, y)];
grid[(x, y)] = grid[(x, y - offset)];
grid[(x, y - offset)] = temp;
}
}
}

View File

@ -160,21 +160,3 @@ macro_rules! is_valid_area {
!(get_y(upper_left) > get_y(bottom_right) || get_x(upper_left) > get_x(bottom_right)) !(get_y(upper_left) > get_y(bottom_right) || get_x(upper_left) > get_x(bottom_right))
}}; }};
} }
/// A `(cols, rows)` size.
pub type Size = (usize, usize);
pub trait HasSize {
fn size(&self) -> Size;
fn cols(&self) -> usize {
self.size().0
}
fn rows(&self) -> usize {
self.size().1
}
}
pub trait HasPosition {
fn origin(&self) -> Pos;
fn set_origin(&mut self, new_origin: Pos);
}