Skip to content

Commit

Permalink
Implement highlights and annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
baskerville committed Oct 18, 2019
1 parent c0d884a commit 9844344
Show file tree
Hide file tree
Showing 60 changed files with 1,766 additions and 585 deletions.
1 change: 1 addition & 0 deletions artworks/swipe_sequences.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 31 additions & 33 deletions doc/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

## Bottom bar

Hold the next/previous page icon to go the last/first page.
Tap and hold the next/previous page icon to go the last/first page.

Tap the matches count label to bring up the library menu.

Expand All @@ -27,37 +27,19 @@ The screen is divided into seven regions:

![Touch Regions](../artworks/touch_regions.svg)

Gestures by region:
Tap gestures by region:

- *LE* (Left Ear):
- Normal Mode:
- Tap: previous page.
- Hold: previous chapter.
- Search Mode:
- Tap: previous results page.
- Hold: first results page.
- *MB* (Middle Band):
- Tap: toggle the top and bottom bars.
- Hold: perform a full screen refresh.
- Normal Mode: previous page.
- Search Mode: previous results page.
- *MB* (Middle Band): toggle the top and bottom bars.
- *RE* (Right Ear):
- Normal Mode:
- Tap: next page.
- Hold: next chapter.
- Search Mode:
- Tap: next results page.
- Hold: last results page.
- *TL* (Top Left Corner):
- Tap: previous location.
- Hold: previous bookmark.
- *TR* (Top Right Corner):
- Tap: toggle bookmark.
- Hold: next bookmark.
- *BL* (Bottom Left Corner):
- Tap: table of contents in normal mode, previous page in search mode.
- Hold: guess the frontlight if there's more than two frontlight presets defined, toggle the frontlight otherwise.
- *BR* (Bottom Right Corner):
- Tap: go to page in normal mode, next page in search mode.
- Hold: toggle the bitonal mode.
- Normal Mode: next page.
- Search Mode: next results page.
- *TL* (Top Left Corner): previous location.
- *TR* (Top Right Corner): toggle bookmark.
- *BL* (Bottom Left Corner): table of contents in normal mode, previous page in search mode.
- *BR* (Bottom Right Corner): go to page in normal mode, next page in search mode.

Swipe west/east to go to the next/previous page.

Expand All @@ -67,21 +49,37 @@ Rotate to change the screen orientation (one finger is the center, the other des

Spread (resp. pinch) horizontally to switch the zoom mode to fit-to-width (resp. fit-to-page).

The following swipe sequences are recognized:

![Swipe Sequences](../artworks/swipe_sequences.svg)

- Arrow west/east: go to the previous/next chapter in normal mode, the first/last results in search mode.
- Arrow north/south: start searching text backward/forward.
- Top left/right corner: go to the previous/next annotation, highlight or bookmark.
- Bottom left corner: guess the frontlight if there's more than two frontlight presets defined, toggle the frontlight otherwise.
- Bottom right corner: toggle the bitonal mode.

### Text Selection

To select text, tap and hold the first or last word of the selection. Wait for the selection feedback. Move your finger on the other end of the selection and lift it. If you've made a mistake, select *Adjust Selection* and tap on the correct ends; tap and hold the selection when you're done.

## Bottom bar

Hold the next/previous page icon to go the next/previous chapter.
Tap and hold the next/previous page icon to go the next/previous chapter.

## Top bar

Tap the title label to bring up the book menu.

# Home & Reader

Tap two diagonally opposite corners to take a screenshot.
Tap the bottom left and top right corners to take a screenshot.

Tap the top left and bottom right corners to do a full screen refresh.

## Menus

You can select a menu entry *without closing the menu* by holding it.
You can select a menu entry *without closing the menu* by tapping and holding it.

## Top bar

Expand All @@ -97,7 +95,7 @@ The *ALT* and *SHIFT* keys can be locked by tapping them twice.

The *CMB* (combine) key can be used to enter special characters, e.g.: `CMB o e` produces `œ`.

A hold on the delete or motion keys will act on words instead of characters.
A tap and hold on the delete or motion keys will act on words instead of characters.

# Annex

Expand Down
2 changes: 1 addition & 1 deletion doc/TODO.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- Dictionary, highlights, annotations.
- Dictionary.
- ePUB renderer: RTL.
- Metadata view.
- Complex/fuzzy search queries?
Expand Down
40 changes: 26 additions & 14 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use fnv::FnvHashMap;
use chrono::Local;
use crate::framebuffer::{Framebuffer, KoboFramebuffer, Display, UpdateMode};
use crate::view::{View, Event, EntryId, EntryKind, ViewId, AppId};
use crate::view::{render, render_no_wait, render_no_wait_region, handle_event, expose};
use crate::view::{render, render_region, render_no_wait, render_no_wait_region, handle_event, expose};
use crate::view::common::{locate, locate_by_id, transfer_notifications, overlapping_rectangle};
use crate::view::frontlight::FrontlightWindow;
use crate::view::menu::{Menu, MenuKind};
Expand Down Expand Up @@ -517,17 +517,16 @@ pub fn run() -> Result<(), Error> {
continue;
}

if view.might_rotate() {
if let Some(rotation_lock) = context.settings.rotation_lock {
let orientation = CURRENT_DEVICE.orientation(n);
if rotation_lock == RotationLock::Current ||
(rotation_lock == RotationLock::Portrait && orientation == Orientation::Landscape) ||
(rotation_lock == RotationLock::Landscape && orientation == Orientation::Portrait) {
continue;
}
if let Some(rotation_lock) = context.settings.rotation_lock {
let orientation = CURRENT_DEVICE.orientation(n);
if rotation_lock == RotationLock::Current ||
(rotation_lock == RotationLock::Portrait && orientation == Orientation::Landscape) ||
(rotation_lock == RotationLock::Landscape && orientation == Orientation::Portrait) {
continue;
}
tx.send(Event::Select(EntryId::Rotate(n))).unwrap();
}

tx.send(Event::Select(EntryId::Rotate(n))).unwrap();
},
DeviceEvent::UserActivity if context.settings.auto_suspend > 0 => {
inactive_since = Instant::now();
Expand Down Expand Up @@ -639,19 +638,26 @@ pub fn run() -> Result<(), Error> {
},
Event::Gesture(ge) => {
match ge {
GestureEvent::HoldButton(ButtonCode::Power) => {
GestureEvent::HoldButtonLong(ButtonCode::Power) => {
power_off(view.as_mut(), &mut history, &mut updating, &mut context);
exit_status = ExitStatus::PowerOff;
break;
},
GestureEvent::MultiTap(points) => {
GestureEvent::MultiTap(mut points) => {
let mut rect = context.fb.rect();
let w = rect.width() as i32;
let h = rect.height() as i32;
let m = w.min(h);
rect.shrink(&Edge::uniform(m / 12));
if points[0].x > points[1].x {
points.swap(0, 1);
}
if points[0].dist2(points[1]) >= rect.diag2() {
tx.send(Event::Select(EntryId::TakeScreenshot)).unwrap();
if points[0].y < points[1].y {
tx.send(Event::Select(EntryId::TakeScreenshot)).unwrap();
} else {
tx.send(Event::Render(context.fb.rect(), UpdateMode::Full)).unwrap();
}
}
},
_ => {
Expand All @@ -678,6 +684,12 @@ pub fn run() -> Result<(), Error> {
updating.insert(tok, rect);
}
},
Event::RenderRegion(mut rect, mode) => {
render_region(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
updating.insert(tok, rect);
}
},
Event::RenderNoWait(mut rect, mode) => {
render_no_wait(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
Expand Down Expand Up @@ -820,7 +832,7 @@ pub fn run() -> Result<(), Error> {
context.settings.intermission_images.insert(key.to_string(), path.clone());
}
},
Event::Select(EntryId::Rotate(n)) if n != context.display.rotation => {
Event::Select(EntryId::Rotate(n)) if n != context.display.rotation && view.might_rotate() => {
updating.retain(|tok, _| context.fb.wait(*tok).is_err());
if let Ok(dims) = context.fb.set_rotation(n) {
raw_sender.send(display_rotate_event(n)).unwrap();
Expand Down
28 changes: 20 additions & 8 deletions src/document/djvu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::rc::Rc;
use std::path::Path;
use std::ffi::{CStr, CString};
use std::os::unix::ffi::OsStrExt;
use super::{Document, Location, BoundedText, TocEntry};
use super::{Document, Location, TextLocation, BoundedText, TocEntry};
use super::{chapter, chapter_relative};
use crate::metadata::TextAlign;
use crate::framebuffer::Pixmap;
Expand Down Expand Up @@ -171,6 +171,7 @@ impl Document for DjvuDocument {
let s_rect = miniexp_symbol(c_rect.as_ptr()) as *mut MiniExp;
let mut link = links;
let mut result = Vec::new();
let mut offset = 0;
while !(*link).is_null() {
let uri = miniexp_nth(1, *link);
let area = miniexp_nth(3, *link);
Expand All @@ -183,8 +184,13 @@ impl Document for DjvuDocument {
let r_height = miniexp_nth(4, area) as i32 >> 2;
bndr![x_min as f32, (y_max - r_height) as f32, (x_min + r_width) as f32, y_max as f32]
};
result.push(BoundedText { text, rect });
result.push(BoundedText {
text,
rect,
location: TextLocation::Static(index, offset),
});
}
offset += 1;
link = link.offset(1);
}
libc::free(links as *mut libc::c_void);
Expand Down Expand Up @@ -278,15 +284,16 @@ impl DjvuDocument {
if exp == MINIEXP_NIL {
None
} else {
let mut words = Vec::new();
Self::walk_text(exp, height, kind, &mut words);
let mut data = Vec::new();
let mut offset = 0;
Self::walk_text(exp, height, kind, index, &mut offset, &mut data);
ddjvu_miniexp_release(self.doc, exp);
Some((words, index))
Some((data, index))
}
}
}

fn walk_text(exp: *mut MiniExp, height: i32, kind: &[u8], data: &mut Vec<BoundedText>) {
fn walk_text(exp: *mut MiniExp, height: i32, kind: &[u8], index: usize, offset: &mut usize, data: &mut Vec<BoundedText>) {
unsafe {
let len = miniexp_length(exp);
let rect = {
Expand All @@ -305,10 +312,15 @@ impl DjvuDocument {
let raw = miniexp_to_str(miniexp_nth(5, exp));
let c_str = CStr::from_ptr(raw);
let text = c_str.to_string_lossy().into_owned();
data.push(BoundedText { rect, text });
*offset += 1;
data.push(BoundedText {
rect,
text,
location: TextLocation::Static(index, *offset),
});
} else if !has_text {
for i in 5..len {
Self::walk_text(miniexp_nth(i, exp), height, kind, data);
Self::walk_text(miniexp_nth(i, exp), height, kind, index, offset, data);
}
}
}
Expand Down
Loading

0 comments on commit 9844344

Please sign in to comment.