From 2a9bd053196deb7710729bc3541e7d5feb9e4856 Mon Sep 17 00:00:00 2001
From: James Campos <james.r.campos@gmail.com>
Date: Mon, 23 Nov 2020 00:35:48 -0800
Subject: toc cursor #8

---
 src/epub.rs |   2 +-
 src/main.rs |   5 +--
 src/view.rs | 102 +++++++++++++++++++++++-------------------------------------
 3 files changed, 43 insertions(+), 66 deletions(-)

(limited to 'src')

diff --git a/src/epub.rs b/src/epub.rs
index 9c53551..496ee96 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -200,7 +200,7 @@ fn render(n: Node, c: &mut Chapter) {
                     c.render(n, Attribute::Underlined, Attribute::NoUnderline);
                     c.links.push((start, c.text.len(), url.to_string()));
                 }
-                _ => c.render_text(n)
+                _ => c.render_text(n),
             }
         }
         "em" => c.render(n, Attribute::Italic, Attribute::NoItalic),
diff --git a/src/main.rs b/src/main.rs
index 0b322c8..1792dfb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -109,9 +109,9 @@ pub struct Bk<'a> {
     max_width: u16,
     // view state
     view: Option<&'a dyn View>,
+    cursor: usize,
     dir: Direction,
     meta: Vec<String>,
-    nav_top: usize,
     query: String,
 }
 
@@ -147,9 +147,9 @@ impl Bk<'_> {
             rows: rows as usize,
             max_width: args.width,
             view: Some(if args.toc { &Nav } else { &Page }),
+            cursor: 0,
             dir: Direction::Next,
             meta,
-            nav_top: 0,
             query: String::new(),
         };
 
@@ -180,6 +180,7 @@ impl Bk<'_> {
             for (i, line) in view.render(self).iter().enumerate() {
                 queue!(stdout, cursor::MoveTo(self.pad(), i as u16), Print(line))?;
             }
+            queue!(stdout, cursor::MoveTo(self.pad(), self.cursor as u16))?;
             stdout.flush().unwrap();
 
             match event::read()? {
diff --git a/src/view.rs b/src/view.rs
index 2f0ecfc..cdb2ceb 100644
--- a/src/view.rs
+++ b/src/view.rs
@@ -5,7 +5,7 @@ use crossterm::{
     },
     style::Attribute,
 };
-use std::cmp::{max, min, Ordering};
+use std::cmp::{min, Ordering};
 use unicode_width::UnicodeWidthChar;
 
 use crate::{get_line, Bk, Direction, SearchArgs};
@@ -106,50 +106,32 @@ PageDown Right Space f l  Page Down
 
 pub struct Nav;
 impl Nav {
-    fn start(&self, bk: &mut Bk) {
-        bk.nav_top = bk.chapter.saturating_sub(bk.rows / 2);
-        bk.mark('\'');
-        bk.view = Some(&Self);
+    fn prev(&self, bk: &mut Bk, n: usize) {
+        bk.chapter = bk.chapter.saturating_sub(n);
+        self.cursor(bk);
     }
-    fn prev_chapter(&self, bk: &mut Bk) {
-        if bk.chapter > 0 {
-            if bk.chapter == bk.nav_top {
-                bk.nav_top -= 1;
-            }
-            bk.chapter -= 1;
-        }
+    fn next(&self, bk: &mut Bk, n: usize) {
+        bk.chapter = min(bk.chapters.len() - 1, bk.chapter + n);
+        self.cursor(bk);
     }
-    fn next_chapter(&self, bk: &mut Bk) {
-        if bk.chapter < bk.chapters.len() - 1 {
-            bk.chapter += 1;
-            if bk.chapter == bk.nav_top + bk.rows {
-                bk.nav_top += 1;
-            }
-        }
-    }
-    fn scroll_down(&self, bk: &mut Bk, n: usize) {
-        bk.nav_top = min(bk.nav_top + n, bk.chapters.len() - 1);
-        bk.chapter = max(bk.chapter, bk.nav_top);
-    }
-    fn scroll_up(&self, bk: &mut Bk, n: usize) {
-        bk.nav_top = bk.nav_top.saturating_sub(n);
-        bk.chapter = min(bk.chapter, bk.nav_top + bk.rows - 1);
+    fn cursor(&self, bk: &mut Bk) {
+        bk.cursor = min(bk.rows / 2, bk.chapter);
     }
     fn click(&self, bk: &mut Bk, row: usize) {
-        if bk.nav_top + row < bk.chapters.len() {
-            bk.chapter = bk.nav_top + row;
+        let start = bk.chapter - bk.cursor;
+        if start + row < bk.chapters.len() {
+            bk.chapter = start + row;
             bk.line = 0;
             bk.view = Some(&Page);
         }
     }
 }
-
 impl View for Nav {
     fn on_mouse(&self, bk: &mut Bk, e: MouseEvent) {
         match e {
             MouseEvent::Down(_, _, row, _) => self.click(bk, row as usize),
-            MouseEvent::ScrollDown(_, _, _) => self.scroll_down(bk, 3),
-            MouseEvent::ScrollUp(_, _, _) => self.scroll_up(bk, 3),
+            MouseEvent::ScrollDown(_, _, _) => self.next(bk, 3),
+            MouseEvent::ScrollUp(_, _, _) => self.prev(bk, 3),
             _ => (),
         }
     }
@@ -163,42 +145,32 @@ impl View for Nav {
                 bk.line = 0;
                 bk.view = Some(&Page);
             }
-            Down | Char('j') => self.next_chapter(bk),
-            Up | Char('k') => self.prev_chapter(bk),
-            Home | Char('g') => {
-                bk.chapter = 0;
-                bk.nav_top = 0;
-            }
-            End | Char('G') => {
-                bk.chapter = bk.chapters.len() - 1;
-                bk.nav_top = bk.chapters.len().saturating_sub(bk.rows);
-            }
-            PageDown | Char('f') => self.scroll_down(bk, bk.rows),
-            PageUp | Char('b') => self.scroll_up(bk, bk.rows),
-            Char('d') => self.scroll_down(bk, bk.rows / 2),
-            Char('u') => self.scroll_up(bk, bk.rows / 2),
+            Down | Char('j') => self.next(bk, 1),
+            Up | Char('k') => self.prev(bk, 1),
+            Home | Char('g') => self.prev(bk, bk.chapters.len()),
+            End | Char('G') => self.next(bk, bk.chapters.len()),
+            PageDown | Char('f') => self.next(bk, bk.rows),
+            PageUp | Char('b') => self.prev(bk, bk.rows),
+            Char('d') => self.next(bk, bk.rows / 2),
+            Char('u') => self.prev(bk, bk.rows / 2),
             _ => (),
         }
     }
     fn render(&self, bk: &Bk) -> Vec<String> {
-        let end = min(bk.nav_top + bk.rows, bk.chapters.len());
+        let start = bk.chapter - bk.cursor;
+        let end = min(bk.chapters.len(), start + bk.rows);
 
-        bk.chapters[bk.nav_top..end]
+        let mut arr = bk.chapters[start..end]
             .iter()
-            .enumerate()
-            .map(|(i, chapter)| {
-                if bk.chapter == bk.nav_top + i {
-                    format!(
-                        "{}{}{}",
-                        Attribute::Reverse,
-                        chapter.title,
-                        Attribute::Reset
-                    )
-                } else {
-                    chapter.title.to_string()
-                }
-            })
-            .collect()
+            .map(|c| c.title.clone())
+            .collect::<Vec<String>>();
+        arr[bk.cursor] = format!(
+            "{}{}{}",
+            Attribute::Reverse,
+            arr[bk.cursor],
+            Attribute::Reset
+        );
+        arr
     }
 }
 
@@ -257,7 +229,11 @@ impl View for Page {
     fn on_key(&self, bk: &mut Bk, kc: KeyCode) {
         match kc {
             Esc | Char('q') => bk.view = None,
-            Tab => Nav.start(bk),
+            Tab => {
+                bk.mark('\'');
+                Nav.cursor(bk);
+                bk.view = Some(&Nav);
+            }
             F(_) => bk.view = Some(&Help),
             Char('m') => bk.view = Some(&Mark),
             Char('\'') => bk.view = Some(&Jump),
-- 
cgit v1.2.3