+use std::cmp::{min, max};
use std::collections::HashMap;
use super::client::{Client, ClientError, FeedId, FeedExtend};
use super::text::*;
use super::tui::{
ActivityState, CursorPosition, LogicalAction,
- OurKey,
+ OurKey, OurKey::*,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
contents: FeedFileContents,
rendered: HashMap<isize, Vec<ColouredString>>,
pos: FilePosition,
- last_width: Option<usize>,
+ last_size: Option<(usize, usize)>,
}
impl FeedFile {
contents: contents,
rendered: HashMap::new(),
pos: initial_pos,
- last_width: None,
+ last_size: None,
};
Ok(ff)
}
self.rendered.get(&index).expect("We just made sure this was present")
}
+ fn ensure_enough_rendered(&mut self) {
+ let (w, h) = self.last_size.expect(
+ "ensure_enough_rendered before resize");
+
+ let (item, line) = self.refine_pos(w);
+
+ let mut item = item;
+ let mut lines_rendered = line;
+ while item > self.contents.origin && lines_rendered + 1 < h {
+ item -= 1;
+ lines_rendered += self.ensure_item_rendered(item, w).len();
+ }
+ }
+
fn refine_pos(&mut self, w: usize) -> (isize, usize) {
let (newpos, item, line) = match self.pos {
pos @ FilePosition::Fine(item, line) => (pos, item, line),
self.pos = newpos;
}
+
+ fn move_up(&mut self, distance: usize) {
+ let (w, _h) = self.last_size.expect("move_up before resize");
+ let (item, line) = match self.pos {
+ FilePosition::Fine(item, line) => (item, line),
+ _ => panic!("coarse position reached move_up()"),
+ };
+
+ let mut item = item;
+ let mut line = line;
+ let mut remaining = distance;
+ while remaining > 0 {
+ let this = min(line, remaining);
+ remaining -= this;
+ line -= this;
+ if line == 0 {
+ if item <= self.contents.origin {
+ break;
+ }
+ item -= 1;
+ line = self.ensure_item_rendered(item, w).len();
+ }
+ }
+ // FIXME: clip position at top of file
+ self.pos = FilePosition::Fine(item, line);
+ self.ensure_enough_rendered();
+ }
}
impl ActivityState for FeedFile {
fn resize(&mut self, w: usize, h: usize) {
- if self.last_width != Some(w) {
- self.last_width = Some(w);
+ if self.last_size != Some((w, h)) {
+ self.last_size = Some((w, h));
self.coarsen_pos();
self.rendered.clear();
}
- let (item, line) = self.refine_pos(w);
-
- let mut item = item;
- let mut lines_rendered = line;
- while item > self.contents.origin && lines_rendered + 1 < h {
- item -= 1;
- lines_rendered += self.ensure_item_rendered(item, w).len();
- }
+ self.ensure_enough_rendered();
}
fn draw(&self, w: usize, h: usize)
-> (Vec<ColouredString>, CursorPosition) {
- assert_eq!(self.last_width, Some(w), "resize() should have done that");
+ assert_eq!(self.last_size, Some((w, h)),
+ "last resize() inconsistent with draw()");
let (start_item, start_line) = match self.pos {
FilePosition::Fine(item, line) => (item, line),
_ => panic!("coarse position reached draw()"),
let mut item = start_item;
let mut lines = Vec::new();
+ let mut at_bottom = item == self.contents.last_index();
+ // Retrieve rendered lines from the bottom of the window upwards
'outer: while item >= self.contents.origin && lines.len() + 1 < h {
let rendered = self.rendered.get(&item)
.expect("unrendered item reached draw()");
let line_limit = if item == start_item {
+ if start_line != rendered.len() {
+ at_bottom = false;
+ }
start_line
} else {
rendered.len()
lines.extend_from_slice(&BlankLine::render_static());
}
- (lines, CursorPosition::None) // FIXME: status line
+ let fs = FileStatusLine::new();
+ let fs = if at_bottom {
+ fs.add(Pr('-'), "Back", 99)
+ } else {
+ fs.add(Space, "Down", 99)
+ };
+ let fs = fs.add(Pr('q'), "Exit", 100)
+ .finalise();
+ // FIXME: document more keys
+ // FIXME: best-effort percentage calculation
+ lines.extend_from_slice(&fs.render(w));
+
+ (lines, CursorPosition::End)
}
- fn handle_keypress(&mut self, _key: OurKey, _client: &mut Client) ->
+ fn handle_keypress(&mut self, key: OurKey, _client: &mut Client) ->
LogicalAction
{
- LogicalAction::Nothing // FIXME
+ let (_w, h) = match self.last_size {
+ Some(size) => size,
+ None => panic!("handle_keypress before resize"),
+ };
+
+ match key {
+ Pr('q') | Pr('Q') => LogicalAction::Pop,
+ Up => {
+ self.move_up(1);
+ LogicalAction::Nothing
+ },
+ Pr('-') | Pr('b') | Pr('B') | PgUp | Left => {
+ self.move_up(max(1, h - min(h, 3)));
+ LogicalAction::Nothing
+ },
+ _ => LogicalAction::Nothing,
+ }
}
}