First try in implementing page caching
Could not find out how to cache in background, so all pages are cached when the document is loaded
This commit is contained in:
parent
11627c8726
commit
ca4d5fc899
@ -22,9 +22,9 @@ fn main() {
|
|||||||
let app = Application::builder().application_id(APP_ID).build();
|
let app = Application::builder().application_id(APP_ID).build();
|
||||||
|
|
||||||
app.connect_activate(move |app| {
|
app.connect_activate(move |app| {
|
||||||
let myui = build_ui(app);
|
let ui = build_ui(app);
|
||||||
if let Some(file) = cli.file.as_ref() {
|
if let Some(file) = cli.file.as_ref() {
|
||||||
ui::load_document(file, Rc::clone(&myui));
|
ui::load_document(file, Rc::clone(&ui));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
170
src/ui.rs
170
src/ui.rs
@ -1,11 +1,11 @@
|
|||||||
use std::{cell::RefCell, path::Path, rc::Rc};
|
use std::{cell::RefCell, collections::BTreeMap, path::Path, rc::Rc, thread, time::Duration};
|
||||||
|
|
||||||
use cairo::{Context, Format, ImageSurface};
|
use cairo::{Context, Format, ImageSurface};
|
||||||
use gtk4::{
|
use gtk4::{
|
||||||
prelude::*, Application, ApplicationWindow, Box, Button, DrawingArea, FileChooserAction,
|
prelude::*, Application, ApplicationWindow, Box, Button, DrawingArea, FileChooserAction,
|
||||||
FileChooserDialog, HeaderBar, Label, Orientation, ResponseType,
|
FileChooserDialog, HeaderBar, Label, Orientation, ResponseType,
|
||||||
};
|
};
|
||||||
use poppler::Page;
|
use poppler::{Document, Page};
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
window: ApplicationWindow,
|
window: ApplicationWindow,
|
||||||
@ -17,46 +17,133 @@ pub struct Ui {
|
|||||||
document_canvas: Option<DocumentCanvas>,
|
document_canvas: Option<DocumentCanvas>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DocumentCanvas {
|
pub struct PageCache {
|
||||||
document: poppler::Document,
|
max_num_pages: usize,
|
||||||
current_page_number: i32,
|
first_page_number: usize,
|
||||||
num_pages: i32,
|
pages: BTreeMap<usize, Rc<Page>>,
|
||||||
page_left: Option<Page>,
|
|
||||||
page_right: Option<Page>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentCanvas {
|
impl PageCache {
|
||||||
pub fn new(document: poppler::Document) -> Self {
|
pub fn new(max_num_pages: usize) -> Self {
|
||||||
let num_pages = document.n_pages();
|
PageCache {
|
||||||
let page_left = document.page(0);
|
max_num_pages,
|
||||||
let page_right = document.page(1);
|
first_page_number: 0,
|
||||||
DocumentCanvas {
|
pages: BTreeMap::new(),
|
||||||
document,
|
|
||||||
num_pages,
|
|
||||||
current_page_number: 1,
|
|
||||||
page_left,
|
|
||||||
page_right,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_page(&self, page_number: usize) -> Option<Rc<Page>> {
|
||||||
|
let index = page_number - self.first_page_number;
|
||||||
|
self.pages.get(&index).map(Rc::clone)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cache_pages(
|
||||||
|
&mut self,
|
||||||
|
current_page_number: usize,
|
||||||
|
page_numbers: Vec<usize>,
|
||||||
|
document: &Document,
|
||||||
|
) {
|
||||||
|
for page_number in page_numbers {
|
||||||
|
if self.pages.contains_key(&page_number) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let page = document.page(page_number as i32);
|
||||||
|
if let Some(page) = page {
|
||||||
|
self.pages.insert(page_number, Rc::new(page));
|
||||||
|
|
||||||
|
if self.pages.len() > self.max_num_pages && self.pages.len() > 2 {
|
||||||
|
let _result = self.remove_most_distant_page(current_page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_most_distant_page(&mut self, current_page_number: usize) -> Result<(), ()> {
|
||||||
|
let (min_cached_page_number, min_cached_page) = self.pages.pop_first().ok_or(())?;
|
||||||
|
let (max_cached_page_number, max_cached_page) = self.pages.pop_last().ok_or(())?;
|
||||||
|
|
||||||
|
if current_page_number.abs_diff(min_cached_page_number)
|
||||||
|
> current_page_number.abs_diff(max_cached_page_number)
|
||||||
|
{
|
||||||
|
self.pages.insert(max_cached_page_number, max_cached_page);
|
||||||
|
} else {
|
||||||
|
self.pages.insert(min_cached_page_number, min_cached_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DocumentCanvas {
|
||||||
|
document: Document,
|
||||||
|
current_page_number: usize,
|
||||||
|
num_pages: usize,
|
||||||
|
page_cache: PageCache,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentCanvas {
|
||||||
|
pub fn new(document: poppler::Document, max_num_cached_pages: usize) -> Self {
|
||||||
|
let num_pages = document.n_pages() as usize;
|
||||||
|
DocumentCanvas {
|
||||||
|
document,
|
||||||
|
num_pages,
|
||||||
|
current_page_number: 0,
|
||||||
|
page_cache: PageCache::new(max_num_cached_pages),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_left_page(&self) -> Option<Rc<Page>> {
|
||||||
|
self.page_cache.get_page(self.current_page_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_right_page(&self) -> Option<Rc<Page>> {
|
||||||
|
self.page_cache.get_page(self.current_page_number + 1)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increase_page_number(&mut self) {
|
pub fn increase_page_number(&mut self) {
|
||||||
if self.current_page_number >= self.num_pages - 1 {
|
if self.current_page_number >= self.num_pages - 2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_page_number += 1;
|
self.current_page_number += 1;
|
||||||
self.page_left = self.page_right.take();
|
|
||||||
self.page_right = self.document.page(self.current_page_number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrease_page_number(&mut self) {
|
pub fn decrease_page_number(&mut self) {
|
||||||
if self.current_page_number <= 1 {
|
if self.current_page_number <= 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_page_number -= 1;
|
self.current_page_number -= 1;
|
||||||
self.page_right = self.page_left.take();
|
}
|
||||||
self.page_left = self.document.page(self.current_page_number - 1);
|
|
||||||
|
pub fn cache_current_two_pages(&mut self) {
|
||||||
|
self.page_cache.cache_pages(
|
||||||
|
self.current_page_number,
|
||||||
|
vec![self.current_page_number, self.current_page_number + 1],
|
||||||
|
&self.document,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cache_surrounding_pages(&mut self) {
|
||||||
|
self.page_cache.cache_pages(
|
||||||
|
self.current_page_number,
|
||||||
|
vec![
|
||||||
|
self.current_page_number.saturating_sub(2),
|
||||||
|
self.current_page_number.saturating_sub(1),
|
||||||
|
self.current_page_number + 2,
|
||||||
|
self.current_page_number + 3,
|
||||||
|
],
|
||||||
|
&self.document,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cache_all_pages(&mut self) {
|
||||||
|
self.page_cache.cache_pages(
|
||||||
|
self.current_page_number,
|
||||||
|
(0..self.document.n_pages() as usize).collect(),
|
||||||
|
&self.document,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +170,8 @@ fn update_page_status(ui: &Ui) {
|
|||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{}-{} / {}",
|
"{}-{} / {}",
|
||||||
doc.current_page_number,
|
|
||||||
doc.current_page_number + 1,
|
doc.current_page_number + 1,
|
||||||
|
doc.current_page_number + 2,
|
||||||
doc.num_pages
|
doc.num_pages
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -186,7 +273,7 @@ impl Ui {
|
|||||||
|
|
||||||
ui.borrow().drawing_area.set_draw_func(
|
ui.borrow().drawing_area.set_draw_func(
|
||||||
glib::clone!(@weak ui => move |area, context, _, _| {
|
glib::clone!(@weak ui => move |area, context, _, _| {
|
||||||
draw(&ui.borrow(), area, context);
|
draw(&mut ui.borrow_mut(), area, context);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -205,7 +292,7 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(ui: &Ui, area: &DrawingArea, context: &Context) {
|
fn draw(ui: &mut Ui, area: &DrawingArea, context: &Context) {
|
||||||
if ui.document_canvas.is_none() {
|
if ui.document_canvas.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -215,6 +302,12 @@ fn draw(ui: &Ui, area: &DrawingArea, context: &Context) {
|
|||||||
} else {
|
} else {
|
||||||
draw_single_page(ui, area, context);
|
draw_single_page(ui, area, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this makes the draw wait
|
||||||
|
// ui.document_canvas
|
||||||
|
// .as_mut()
|
||||||
|
// .unwrap()
|
||||||
|
// .cache_surrounding_pages();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_two_pages(ui: &Ui, area: &DrawingArea, context: &Context) {
|
fn draw_two_pages(ui: &Ui, area: &DrawingArea, context: &Context) {
|
||||||
@ -223,12 +316,16 @@ fn draw_two_pages(ui: &Ui, area: &DrawingArea, context: &Context) {
|
|||||||
}
|
}
|
||||||
let document_canvas = ui.document_canvas.as_ref().unwrap();
|
let document_canvas = ui.document_canvas.as_ref().unwrap();
|
||||||
|
|
||||||
if document_canvas.page_left.is_none() || document_canvas.page_right.is_none() {
|
let page_left = document_canvas.get_left_page();
|
||||||
|
let page_right = document_canvas.get_right_page();
|
||||||
|
|
||||||
|
if page_left.is_none() || page_right.is_none() {
|
||||||
|
// TODO: show error message
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let page_left = document_canvas.page_left.as_ref().unwrap();
|
let page_left = page_left.unwrap();
|
||||||
let page_right = document_canvas.page_right.as_ref().unwrap();
|
let page_right = page_right.unwrap();
|
||||||
|
|
||||||
// Add white background
|
// Add white background
|
||||||
// context.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
// context.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
@ -290,11 +387,12 @@ fn draw_single_page(ui: &Ui, area: &DrawingArea, context: &Context) {
|
|||||||
}
|
}
|
||||||
let document_canvas = ui.document_canvas.as_ref().unwrap();
|
let document_canvas = ui.document_canvas.as_ref().unwrap();
|
||||||
|
|
||||||
if document_canvas.page_left.is_none() {
|
if document_canvas.get_left_page().is_none() {
|
||||||
|
// TODO: show error message
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let page = document_canvas.page_left.as_ref().unwrap();
|
let page = document_canvas.get_left_page().unwrap();
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
// context.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
// context.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
@ -359,7 +457,11 @@ pub fn load_document(file: impl AsRef<Path>, ui: Rc<RefCell<Ui>>) {
|
|||||||
println!("Loading file...");
|
println!("Loading file...");
|
||||||
// TODO: catch errors, maybe show error dialog
|
// TODO: catch errors, maybe show error dialog
|
||||||
let uri = format!("file://{}", file.as_ref().to_str().unwrap());
|
let uri = format!("file://{}", file.as_ref().to_str().unwrap());
|
||||||
let document_canvas = DocumentCanvas::new(poppler::Document::from_file(&uri, None).unwrap());
|
let mut document_canvas =
|
||||||
|
DocumentCanvas::new(poppler::Document::from_file(&uri, None).unwrap(), 1000);
|
||||||
|
// document_canvas.cache_current_two_pages();
|
||||||
|
document_canvas.cache_all_pages();
|
||||||
|
|
||||||
ui.borrow_mut().document_canvas = Some(document_canvas);
|
ui.borrow_mut().document_canvas = Some(document_canvas);
|
||||||
|
|
||||||
update_page_status(&ui.borrow());
|
update_page_status(&ui.borrow());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user