using Adw;
using Gtk;
namespace PpubViewer {
public class ViewerWindow : Adw.ApplicationWindow {
private Adw.HeaderBar header_bar;
private Box box;
private Flap flap;
private DocumentView.DocumentViewManager document_view;
private Button back_button;
private Button forward_button;
private Button properties_button;
private Button menu_button;
private PopoverMenu menu;
private ZoomSpinButton zoom_spin;
private Ppub.Publication publication;
private NavigationHistoryItem current_page = null;
private WindowTitle window_title;
public ViewerWindow(Adw.Application app) {
application = app;
header_bar = new Adw.HeaderBar ();
window_title = new WindowTitle("PPUB Viewer", "");
flap = new Flap();
box = new Box (Orientation.VERTICAL, 0);
box.append (header_bar);
box.append (flap);
content = box;
header_bar.show_end_title_buttons = true;
default_width = 900;
default_height = 700;
header_bar.title_widget = window_title;
flap.separator = new Separator(Orientation.VERTICAL);
properties_button = new Button.from_icon_name("sidebar-show-symbolic");
header_bar.pack_start(properties_button);
header_bar.pack_start(new Separator(Orientation.VERTICAL));
back_button = new Button.from_icon_name("go-previous-symbolic");
back_button.sensitive = false;
back_button.clicked.connect(go_back);
header_bar.pack_start(back_button);
forward_button = new Button.from_icon_name("go-next-symbolic");
forward_button.sensitive = false;
forward_button.clicked.connect(go_forward);
header_bar.pack_start(forward_button);
// menu = new PopoverMenu.from_model(null);
// header_bar.pack_end(menu);
// menu_button = new Button.from_icon_name("open-menu-symbolic");
// menu_button.clicked.connect(() => menu.popup());
// header_bar.pack_end(menu_button);
var zoom_squeezer = new Squeezer();
zoom_squeezer.transition_type = SqueezerTransitionType.CROSSFADE;
zoom_spin = new ZoomSpinButton(false);
var zoom_spin_small = new ZoomSpinButton(true);
zoom_spin_small.adjustment = zoom_spin.adjustment;
zoom_squeezer.add(zoom_spin);
zoom_squeezer.add(zoom_spin_small);
zoom_spin.zoom_level_changed.connect(change_zoom);
header_bar.pack_end(zoom_squeezer);
document_view = new DocumentView.DocumentViewManager();
document_view.link_clicked.connect(link_clicked);
flap.content = document_view;
properties_button.clicked.connect(() => {
flap.reveal_flap = !flap.reveal_flap;
});
}
public void load_ppub(File file) throws Error {
publication = new Ppub.Publication(file.get_path());
var asset = publication.get_default_asset ();
window_title.title = publication.metadata.title ?? "Untitled PPUB";
window_title.subtitle = publication.metadata.author_name ?? "";
title = window_title.title + " - PPUB Viewer";
var scroller = new ScrolledWindow();
scroller.add_css_class("background");
scroller.hscrollbar_policy = PolicyType.NEVER;
var pane = new PropertiesPane(publication.metadata, false);
scroller.child = pane;
pane.link_clicked.connect(property_link_clicked);
flap.flap = scroller;
navigate(asset.name);
}
public void navigate(string file) {
if(current_page == null) {
current_page = new NavigationHistoryItem();
current_page.file_name = file;
current_page.scroll_position = 0;
}
else {
current_page = current_page.add_next(file, document_view.get_scroll_position());
}
load_document(file);
}
public void go_back() {
current_page.scroll_position = document_view.get_scroll_position();
current_page = current_page.previous;
load_document(current_page.file_name);
}
public void go_forward() {
current_page.scroll_position = document_view.get_scroll_position();
current_page = current_page.next;
load_document(current_page.file_name);
}
public void load_document(string file) {
back_button.sensitive = current_page.previous != null;
forward_button.sensitive = current_page.next != null;
document_view.load_asset(publication, publication.get_asset(file));
Idle.add_once(() => {
document_view.set_scroll_position(current_page.scroll_position);
return false;
});
}
private void link_clicked(string url) {
var asset = publication.get_asset(Uri.unescape_string(url));
if(asset != null) {
navigate(asset.name);
return;
}
Uri uri;
try{
uri = Uri.parse(url, UriFlags.PARSE_RELAXED);
}
catch {
var dialog = new Adw.MessageDialog(this, "Unrecognised link", @"Could not determine how to handle the link $url.");
dialog.body_use_markup = true;
dialog.add_response("close", "Close");
dialog.present();
dialog.response.connect(() => dialog.close());
return;
}
var app = AppInfo.get_default_for_uri_scheme(uri.get_scheme());
if(app == null) {
var dialog = new Adw.MessageDialog(this, "No application", @"Could not find an application to handle the URI $uri.");
dialog.body_use_markup = true;
dialog.add_response("close", "Close");
dialog.present();
dialog.response.connect(() => dialog.close());
return;
}
var uris = new List();
uris.append(uri.to_string());
var dialog = new Adw.MessageDialog(this, "Open external link?", @"Do you want to open the external link $uri?");
dialog.body_use_markup = true;
dialog.add_response("cancel", @"Cancel");
dialog.add_response("open", @"Open in $(app.get_display_name())");
dialog.present();
dialog.response.connect(id => {
if(id == "open") {
app.launch_uris(uris, null);
}
dialog.close();
});
}
private void property_link_clicked(string file) {
link_clicked(file);
if(flap.folded) {
flap.reveal_flap = false;
}
}
private void change_zoom(int percent) {
document_view.set_zoom_percentage(percent);
}
public override void size_allocate(int width, int height, int baseline) {
base.size_allocate(width, height, baseline);
document_view.reflow();
}
}
}