1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use anyhow::anyhow;
use gdk::enums::key;
use gtk::prelude::*;
use gtk::{Window, WindowType, HeaderBar};
use log::{debug, warn};
use webkit2gtk::{WebContext, WebView, WebViewExt};
use crate::assets::Assets;
#[derive(Debug)]
pub enum Event {
LoadHtml(String),
Reload,
}
#[derive(Clone)]
pub struct App {
window: Window,
header_bar: HeaderBar,
webview: WebView,
assets: Assets,
}
impl App {
pub fn init(title: Option<&str>) -> anyhow::Result<Self> {
let window = Window::new(WindowType::Toplevel);
window.set_default_size(1024, 768);
let header_bar = HeaderBar::new();
header_bar.set_title(Some("Quickmd"));
header_bar.set_show_close_button(true);
header_bar.set_title(title);
let web_context = WebContext::get_default().
ok_or_else(|| anyhow!("Couldn't initialize GTK WebContext"))?;
let webview = WebView::new_with_context(&web_context);
window.set_titlebar(Some(&header_bar));
window.add(&webview);
let assets = Assets::init()?;
Ok(App { window, header_bar, webview, assets })
}
pub fn init_render_loop(&self, ui_receiver: glib::Receiver<Event>) {
let mut app_clone = self.clone();
ui_receiver.attach(None, move |event| {
match event {
Event::LoadHtml(html) => {
app_clone.load_html(&html).
unwrap_or_else(|e| warn!("Couldn't update HTML: {}", e))
},
Event::Reload => app_clone.reload(),
}
glib::Continue(true)
});
}
pub fn run(&self) {
self.connect_events();
self.window.show_all();
gtk::main();
}
fn load_html(&mut self, html: &str) -> anyhow::Result<()> {
let scroll_top = self.webview.get_title().
and_then(|t| t.parse::<f64>().ok()).
unwrap_or(0.0);
let output_path = self.assets.build(html, scroll_top)?;
debug!("Loading HTML:");
debug!(" > output_path = {}", output_path.display());
self.webview.load_uri(&format!("file://{}", output_path.display()));
Ok(())
}
fn reload(&self) {
self.webview.reload();
}
fn connect_events(&self) {
use std::cell::RefCell;
let self_clone = RefCell::new(Some(self.clone()));
self.window.connect_key_press_event(move |_window, gdk| {
if let key::Escape = gdk.get_keyval() {
self_clone.borrow_mut().take().unwrap().assets.delete();
gtk::main_quit()
}
Inhibit(false)
});
self.window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
}
}