decoder: Use image-rs, libheif-rs, librsvg
This adds proper support for a lot of image formats including SVGs. It will be the basis for many features to come. The technical core is an asynchronous renderer that can arrange textures in smaller tiles which might be generated on demand. Closes #34, #40, #41, #49 Basis for fixing the following issues #7, #27, #36, #43, #68, #71
This commit is contained in:
parent
4d4bc4bb38
commit
f80ec7db56
20 changed files with 3023 additions and 370 deletions
|
|
@ -27,7 +27,6 @@ use gtk::CompositeTemplate;
|
|||
use gtk_macros::spawn;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
mod imp {
|
||||
|
|
@ -52,9 +51,6 @@ mod imp {
|
|||
pub(super) right_click_gesture: TemplateChild<gtk::GestureClick>,
|
||||
#[template_child]
|
||||
pub(super) press_gesture: TemplateChild<gtk::GestureLongPress>,
|
||||
|
||||
/// set if an error has occurred and is shown on error_page
|
||||
pub(super) error: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
|
@ -75,12 +71,9 @@ mod imp {
|
|||
impl ObjectImpl for LpImagePage {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![
|
||||
glib::ParamSpecObject::builder::<LpImage>("image")
|
||||
.read_only()
|
||||
.build(),
|
||||
glib::ParamSpecString::builder("error").read_only().build(),
|
||||
]
|
||||
vec![glib::ParamSpecObject::builder::<LpImage>("image")
|
||||
.read_only()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
|
|
@ -90,7 +83,6 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
match pspec.name() {
|
||||
"image" => obj.image().to_value(),
|
||||
"error" => obj.error().to_value(),
|
||||
name => unimplemented!("property {name}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -112,6 +104,30 @@ mod imp {
|
|||
obj.show_popover_at(x, y);
|
||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||
}));
|
||||
|
||||
obj.image().connect_notify_local(
|
||||
Some("is-loaded"),
|
||||
clone!(@weak obj => move |_,_| {
|
||||
if obj.image().is_loaded() {
|
||||
obj.imp()
|
||||
.stack
|
||||
.set_visible_child(&*obj.imp().scrolled_window);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
obj.image().connect_notify_local(
|
||||
Some("error"),
|
||||
clone!(@weak obj => move |_,_| {
|
||||
if obj.image().error().is_some() {
|
||||
obj.imp().stack.set_visible_child(&*obj.imp().error_page);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Do not waste CPU on spinner if it is not visible
|
||||
self.spinner.connect_map(|s| s.start());
|
||||
self.spinner.connect_unmap(|s| s.stop());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,19 +155,7 @@ impl LpImagePage {
|
|||
|
||||
spawn!(clone!(@weak obj, @strong path => async move {
|
||||
let imp = obj.imp();
|
||||
match imp.image.load(&path).await {
|
||||
Ok(()) => {
|
||||
imp.stack.set_visible_child(&*imp.scrolled_window);
|
||||
imp.spinner.set_spinning(false);
|
||||
},
|
||||
Err(e) => {
|
||||
imp.error.replace(Some(e.to_string()));
|
||||
imp.stack.set_visible_child(&*imp.error_page);
|
||||
obj.notify("error");
|
||||
imp.spinner.set_spinning(false);
|
||||
log::error!("Could not load image: {e}");
|
||||
}
|
||||
}
|
||||
imp.image.load(&path).await;
|
||||
}));
|
||||
|
||||
obj
|
||||
|
|
@ -169,10 +173,6 @@ impl LpImagePage {
|
|||
self.imp().image.texture()
|
||||
}
|
||||
|
||||
pub fn error(&self) -> Option<String> {
|
||||
self.imp().error.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn content_provider(&self) -> Option<gdk::ContentProvider> {
|
||||
self.imp().image.content_provider()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue