aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grid.rs88
-rw-r--r--src/main.rs18
-rw-r--r--src/renderer/mod.rs27
-rw-r--r--src/term.rs74
4 files changed, 196 insertions, 11 deletions
diff --git a/src/grid.rs b/src/grid.rs
index 42dcf210..3ce0a036 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -1,6 +1,7 @@
//! Functions for computing properties of the terminal grid
use std::ops::{Index, IndexMut, Deref, DerefMut, Range, RangeTo, RangeFrom};
+use std::cmp::Ordering;
use std::slice::{Iter, IterMut};
use util::Rotate;
@@ -104,12 +105,55 @@ impl Grid {
self.clear_region(region);
}
- pub fn clear_region(&mut self, region: Range<usize>) {
- for row in self.raw[region].iter_mut() {
- for cell in row.iter_mut() {
- cell.reset();
- }
+ pub fn resize(&mut self, rows: usize, cols: usize) {
+ // Check that there's actually work to do and return early if not
+ if rows == self.rows && cols == self.cols {
+ return;
+ }
+
+ match self.rows.cmp(&rows) {
+ Ordering::Less => self.grow_rows(rows),
+ Ordering::Greater => self.shrink_rows(rows),
+ Ordering::Equal => (),
+ }
+
+ match self.cols.cmp(&cols) {
+ Ordering::Less => self.grow_cols(cols),
+ Ordering::Greater => self.shrink_cols(cols),
+ Ordering::Equal => (),
+ }
+ }
+
+ fn grow_rows(&mut self, rows: usize) {
+ for _ in self.num_rows()..rows {
+ self.raw.push(Row::new(self.cols));
+ }
+
+ self.rows = rows;
+ }
+
+ fn shrink_rows(&mut self, rows: usize) {
+ while self.raw.len() != rows {
+ self.raw.pop();
}
+
+ self.rows = rows;
+ }
+
+ fn grow_cols(&mut self, cols: usize) {
+ for row in self.rows_mut() {
+ row.grow(cols);
+ }
+
+ self.cols = cols;
+ }
+
+ fn shrink_cols(&mut self, cols: usize) {
+ for row in self.rows_mut() {
+ row.shrink(cols);
+ }
+
+ self.cols = cols;
}
}
@@ -154,6 +198,18 @@ impl Row {
Row(vec![Cell::new(' '); columns])
}
+ pub fn grow(&mut self, cols: usize) {
+ while self.len() != cols {
+ self.push(Cell::new(' '));
+ }
+ }
+
+ pub fn shrink(&mut self, cols: usize) {
+ while self.len() != cols {
+ self.pop();
+ }
+ }
+
pub fn cells(&self) -> Iter<Cell> {
self.0.iter()
}
@@ -221,3 +277,25 @@ impl IndexMut<RangeTo<usize>> for Row {
&mut self.0[index]
}
}
+
+pub trait ClearRegion<T> {
+ fn clear_region(&mut self, region: T);
+}
+
+macro_rules! clear_region_impl {
+ ($range:ty) => {
+ impl ClearRegion<$range> for Grid {
+ fn clear_region(&mut self, region: $range) {
+ for row in self.raw[region].iter_mut() {
+ for cell in row.iter_mut() {
+ cell.reset();
+ }
+ }
+ }
+ }
+ }
+}
+
+clear_region_impl!(Range<usize>);
+clear_region_impl!(RangeTo<usize>);
+clear_region_impl!(RangeFrom<usize>);
diff --git a/src/main.rs b/src/main.rs
index 49f2655e..de0ea05e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -65,6 +65,7 @@ fn handle_event<W>(event: Event,
writer: &mut W,
terminal: &mut Term,
pty_parser: &mut ansi::Parser,
+ render_tx: &mpsc::Sender<(u32, u32)>,
input_processor: &mut input::Processor) -> ShouldExit
where W: Write
{
@@ -78,6 +79,10 @@ fn handle_event<W>(event: Event,
let encoded = c.encode_utf8();
writer.write(encoded.as_slice()).unwrap();
},
+ glutin::Event::Resized(w, h) => {
+ terminal.resize(w as f32, h as f32);
+ render_tx.send((w, h)).expect("render thread active");
+ },
glutin::Event::KeyboardInput(state, _code, key) => {
input_processor.process(state, key, &mut WriteNotifier(writer), *terminal.mode())
},
@@ -165,6 +170,8 @@ fn main() {
let window = Arc::new(window);
let window_ref = window.clone();
+ let (render_tx, render_rx) = mpsc::channel::<(u32, u32)>();
+
let update_thread = thread::spawn_named("Update", move || {
'main_loop: loop {
let mut writer = BufWriter::new(&writer);
@@ -192,6 +199,7 @@ fn main() {
&mut writer,
&mut *terminal,
&mut pty_parser,
+ &render_tx,
&mut input_processor);
if res == ShouldExit::Yes {
break;
@@ -205,6 +213,7 @@ fn main() {
&mut writer,
&mut *terminal,
&mut pty_parser,
+ &render_tx,
&mut input_processor);
if res == ShouldExit::Yes {
@@ -249,6 +258,15 @@ fn main() {
gl::Clear(gl::COLOR_BUFFER_BIT);
}
+ // Receive any resize events; only call gl::Viewport on last available
+ let mut new_size = None;
+ while let Ok(val) = render_rx.try_recv() {
+ new_size = Some(val);
+ }
+ if let Some((w, h)) = new_size.take() {
+ renderer.resize(w as i32, h as i32);
+ }
+
// Need scope so lock is released when swap_buffers is called
{
// Flag that it's time for render
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 9df4052d..8e548dd3 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -478,6 +478,18 @@ impl QuadRenderer {
self.active_tex = 0;
self.program = program;
}
+
+ pub fn resize(&mut self, width: i32, height: i32) {
+ // viewport
+ unsafe {
+ gl::Viewport(0, 0, width, height);
+ }
+
+ // update projection
+ self.program.activate();
+ self.program.update_projection(width as f32, height as f32);
+ self.program.deactivate();
+ }
}
impl<'a> RenderApi<'a> {
@@ -665,20 +677,25 @@ impl ShaderProgram {
u_background: background,
};
+ shader.update_projection(width as f32, height as f32);
+
+ shader.deactivate();
+
+ Ok(shader)
+ }
+
+ fn update_projection(&self, width: f32, height: f32) {
// set projection uniform
- let ortho = cgmath::ortho(0., width as f32, 0., height as f32, -1., 1.);
+ let ortho = cgmath::ortho(0., width, 0., height, -1., 1.);
let projection: [[f32; 4]; 4] = ortho.into();
println!("width: {}, height: {}", width, height);
unsafe {
- gl::UniformMatrix4fv(shader.u_projection,
+ gl::UniformMatrix4fv(self.u_projection,
1, gl::FALSE, projection.as_ptr() as *const _);
}
- shader.deactivate();
-
- Ok(shader)
}
fn set_term_uniforms(&self, props: &term::SizeInfo) {
diff --git a/src/term.rs b/src/term.rs
index c11a0d08..d4168ead 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -2,10 +2,21 @@
use std::ops::Range;
use ansi::{self, Attr};
-use grid::{self, Grid, CellFlags};
+use grid::{self, Grid, CellFlags, ClearRegion};
use tty;
use ::Rgb;
+/// coerce val to be between min and max
+fn limit<T: PartialOrd>(val: T, min: T, max: T) -> T {
+ if val < min {
+ min
+ } else if val > max {
+ max
+ } else {
+ val
+ }
+}
+
/// tomorrow night bright
///
/// because contrast
@@ -190,6 +201,67 @@ impl Term {
}
}
+ /// Resize terminal to new dimensions
+ pub fn resize(&mut self, width: f32, height: f32) {
+ let size = SizeInfo {
+ width: width,
+ height: height,
+ cell_width: self.size_info.cell_width,
+ cell_height: self.size_info.cell_height,
+ };
+
+ let old_cols = self.size_info.cols();
+ let old_rows = self.size_info.rows();
+ let num_cols = size.cols();
+ let num_rows = size.rows();
+
+ self.size_info = size;
+
+ if old_cols == num_cols && old_rows == num_rows {
+ return;
+ }
+
+ // Scroll up to keep cursor and as much context as possible in grid. This only runs when the
+ // rows decreases.
+ self.scroll_region = 0..self.grid.num_rows();
+ // XXX why is +1 required?
+ let row_diff = (self.cursor_y() as isize - num_rows as isize) + 1;
+ if row_diff > 0 {
+ self.scroll(row_diff);
+ self.cursor.advance(-row_diff as i64, 0);
+ }
+
+ println!("num_cols, num_rows = {}, {}", num_cols, num_rows);
+
+ // Resize grids to new size
+ self.grid.resize(num_rows, num_cols);
+ self.alt_grid.resize(num_rows, num_cols);
+
+ // Ensure cursor is in-bounds
+ self.cursor.y = limit(self.cursor.y, 0, num_rows as u16);
+ self.cursor.x = limit(self.cursor.x, 0, num_cols as u16);
+
+ // Recreate tabs list
+ self.tabs = (0..self.grid.num_cols()).map(|i| i % TAB_SPACES == 0)
+ .collect::<Vec<bool>>();
+
+ // Make sure bottom of terminal is clear
+ if row_diff > 0 {
+ self.grid.clear_region((self.cursor.y as usize)..);
+ self.alt_grid.clear_region((self.cursor.y as usize)..);
+ }
+
+ // Reset scrolling region to new size
+ self.scroll_region = 0..self.grid.num_rows();
+
+ // Inform tty of new dimensions
+ self.tty.resize(num_rows,
+ num_cols,
+ self.size_info.width as usize,
+ self.size_info.height as usize);
+
+ }
+
#[inline]
pub fn tty(&self) -> &tty::Tty {
&self.tty