pub mod line;
use std::cmp::{max, min};
use std::mem;
use std::str;
use termbox_simple::Termbox;
use config::Colors;
pub use self::line::Line;
pub use self::line::SegStyle;
pub struct MsgArea {
lines : Vec<Line>,
width : i32,
height : i32,
scroll : i32,
line_buf : Line,
}
impl MsgArea {
pub fn new(width : i32, height : i32) -> MsgArea {
MsgArea {
lines: Vec::new(),
width: width,
height: height,
scroll: 0,
line_buf: Line::new(),
}
}
pub fn resize(&mut self, width : i32, height : i32) {
self.width = width;
self.height = height;
}
pub fn draw(&self, tb: &mut Termbox, colors: &Colors, pos_x: i32, pos_y: i32) {
let mut row = pos_y + self.height - 1;
let mut line_idx = ((self.lines.len() as i32) - 1) - self.scroll;
while line_idx >= 0 && row >= pos_y {
let line = unsafe { self.lines.get_unchecked(line_idx as usize) };
let line_height = line.rendered_height(self.width);
let line_row = row - line_height + 1;
if line_row >= pos_y {
line.draw(tb, colors, pos_x, line_row, self.width);
row = line_row - 1;
line_idx -= 1;
} else {
let render_from = pos_y - line_row;
line.draw_from(tb, colors, pos_x, line_row, render_from, self.width);
break;
}
}
}
}
impl MsgArea {
pub fn scroll_up(&mut self) {
if self.scroll < (self.lines.len() as i32) - 1 {
self.scroll += 1;
}
}
pub fn scroll_down(&mut self) {
if self.scroll > 0 {
self.scroll -= 1;
}
}
pub fn scroll_top(&mut self) {
if self.lines.is_empty() { return; }
let mut height_left = self.height;
let mut i = 0;
while i < self.lines.len() {
let rendered = self.lines[i].rendered_height(self.width);
if height_left < rendered {
break;
}
height_left -= rendered;
i += 1;
}
self.scroll = (self.lines.len() - i) as i32;
}
pub fn scroll_bottom(&mut self) {
self.scroll = 0;
}
pub fn page_up(&mut self) {
self.scroll = max(0, min((self.lines.len() as i32) - 1, self.scroll + 10));
}
pub fn page_down(&mut self) {
self.scroll = max(0, self.scroll - 10);
}
}
impl MsgArea {
pub fn set_style(&mut self, style: SegStyle) {
self.line_buf.set_style(style);
}
pub fn add_text(&mut self, str : &str) {
self.line_buf.add_text(str);
}
pub fn add_char(&mut self, char : char) {
self.line_buf.add_char(char);
}
pub fn flush_line(&mut self) -> usize {
self.lines.push(mem::replace(&mut self.line_buf, Line::new()));
if self.scroll != 0 {
self.scroll += 1;
}
self.lines.len() - 1
}
#[inline]
pub fn modify_line<F>(&mut self, idx : usize, f : F) where F : Fn(&mut Line) {
f(&mut self.lines[idx]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn newline_scrolling() {
let mut msg_area = MsgArea::new(100, 1);
assert_eq!(msg_area.scroll, 0);
msg_area.add_text("line1");
msg_area.flush_line();
assert_eq!(msg_area.scroll, 0);
msg_area.add_text("line2");
msg_area.flush_line();
assert_eq!(msg_area.scroll, 0);
msg_area.scroll_up();
assert_eq!(msg_area.scroll, 1);
msg_area.add_text("line3");
msg_area.flush_line();
assert_eq!(msg_area.scroll, 2);
}
}