diff --git a/src/view/edit_view.rs b/src/view/edit_view.rs index f250fdb..4f0ec11 100644 --- a/src/view/edit_view.rs +++ b/src/view/edit_view.rs @@ -1,16 +1,28 @@ use ncurses; +use std::cmp::min; + use theme::ColorPair; use vec::Vec2; use view::{View,IdView,SizeRequest}; use event::*; use printer::Printer; -/// Displays an editable text. +/// Input box where the user can enter and edit text. pub struct EditView { + /// Current content content: String, + /// Cursor position in the content cursor: usize, + /// Minimum layout length asked to the parent min_length: usize, + + /// When the content is too long for the display, offset it + offset: usize, + /// Last display length, to know the possible offset range + last_length: usize, + // scrollable: bool, + // TODO: add a max text length? } impl EditView { @@ -19,12 +31,16 @@ impl EditView { EditView { content: String::new(), cursor: 0, + offset: 0, min_length: 1, + last_length: 0, + // scrollable: false, } } /// Replace the entire content of the view with the given one. pub fn set_content<'a>(&mut self, content: &'a str) { + self.offset = 0; self.content = content.to_string(); } @@ -67,8 +83,18 @@ impl View for EditView { let len = self.content.chars().count(); printer.with_color(ColorPair::Secondary, |printer| { printer.with_style(ncurses::A_REVERSE(), |printer| { - printer.print((0,0), &self.content); - printer.print_hline((len,0), printer.size.x-len, '_' as u64); + if len < self.last_length { + printer.print((0,0), &self.content); + printer.print_hline((len,0), printer.size.x-len, '_' as u64); + } else { + let visible_end = min(self.content.len(), self.offset + self.last_length); + + let content = &self.content[self.offset..visible_end]; + printer.print((0,0), content); + if visible_end - self.offset < printer.size.x { + printer.print((printer.size.x-1,0), "_"); + } + } }); // Now print cursor @@ -79,11 +105,15 @@ impl View for EditView { // Get the char from the string... Is it so hard? self.content.chars().nth(self.cursor).expect(&format!("Found no char at cursor {} in {}", self.cursor, self.content)) }; - printer.print_hline((self.cursor, 0), 1, c as u64); + printer.print_hline((self.cursor-self.offset, 0), 1, c as u64); } }); } + fn layout(&mut self, size: Vec2) { + self.last_length = size.x; + } + fn get_min_size(&self, _: SizeRequest) -> Vec2 { Vec2::new(self.min_length, 1) } @@ -102,8 +132,8 @@ impl View for EditView { None => self.content.push(ch), Some((i,_)) => self.content.insert(i, ch), } + // TODO: handle wide (CJK) chars self.cursor += 1; - return EventResult::Consumed(None); }, Event::KeyEvent(key) => match key { Key::Home => self.cursor = 0, @@ -113,10 +143,26 @@ impl View for EditView { Key::Backspace if self.cursor > 0 => { self.cursor -= 1; remove_char(&mut self.content, self.cursor); }, Key::Del if self.cursor < self.content.chars().count() => { remove_char(&mut self.content, self.cursor); }, _ => return EventResult::Ignored, - }, } + // Keep cursor in [offset, offset+last_length] by changing offset + // So keep offset in [last_length-cursor,cursor] + // Also call this on resize, but right now it is an event like any other + if self.cursor >= self.offset + self.last_length { + self.offset = self.cursor - self.last_length + 1; + } else if self.cursor < self.offset { + self.offset = self.cursor; + } + if self.offset + self.last_length > self.content.len() + 1{ + + self.offset = if self.content.len() > self.last_length { + self.content.len() - self.last_length + 1 + } else { + 0 + }; + } + EventResult::Consumed(None) } }