image_view: Load images once
We don't need to load the file twice just to get the dimensions. We can load a GdkTexture, use it's APIs for the width and height, and return that as a result to the window. This allows us to kill the `dimensions-loaded` signal and one of the places where we need to load a file.
This commit is contained in:
parent
e0820e0881
commit
945aff3029
2 changed files with 31 additions and 70 deletions
|
|
@ -36,7 +36,6 @@ use crate::util;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
use glib::subclass;
|
|
||||||
|
|
||||||
#[derive(Debug, Default, CompositeTemplate)]
|
#[derive(Debug, Default, CompositeTemplate)]
|
||||||
#[template(resource = "/org/gnome/Loupe/gtk/image_view.ui")]
|
#[template(resource = "/org/gnome/Loupe/gtk/image_view.ui")]
|
||||||
|
|
@ -58,6 +57,7 @@ mod imp {
|
||||||
|
|
||||||
pub directory: RefCell<Option<String>>,
|
pub directory: RefCell<Option<String>>,
|
||||||
pub filename: RefCell<Option<String>>,
|
pub filename: RefCell<Option<String>>,
|
||||||
|
pub uri: RefCell<Option<String>>,
|
||||||
// Path of filenames
|
// Path of filenames
|
||||||
pub directory_pictures: RefCell<Vec<String>>,
|
pub directory_pictures: RefCell<Vec<String>>,
|
||||||
// Cell<T> allows for interior mutability of primitive types
|
// Cell<T> allows for interior mutability of primitive types
|
||||||
|
|
@ -111,26 +111,6 @@ mod imp {
|
||||||
PROPERTIES.as_ref()
|
PROPERTIES.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signals() -> &'static [glib::subclass::Signal] {
|
|
||||||
static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
|
|
||||||
vec![subclass::Signal::builder(
|
|
||||||
// Called when the dimensions of the image
|
|
||||||
// have been found.
|
|
||||||
"dimensions-loaded",
|
|
||||||
&[
|
|
||||||
// The width of the image
|
|
||||||
i32::static_type().into(),
|
|
||||||
// The height of the image
|
|
||||||
i32::static_type().into(),
|
|
||||||
],
|
|
||||||
glib::Type::UNIT.into(),
|
|
||||||
)
|
|
||||||
.build()]
|
|
||||||
});
|
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn property(&self, _obj: &Self::Type, _id: usize, psec: &glib::ParamSpec) -> glib::Value {
|
fn property(&self, _obj: &Self::Type, _id: usize, psec: &glib::ParamSpec) -> glib::Value {
|
||||||
match psec.name() {
|
match psec.name() {
|
||||||
"filename" => self.filename.borrow().to_value(),
|
"filename" => self.filename.borrow().to_value(),
|
||||||
|
|
@ -171,23 +151,30 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IvImageView {
|
impl IvImageView {
|
||||||
pub fn set_image_from_file(&self, file: &gio::File) {
|
pub fn set_image_from_file(&self, file: &gio::File) -> anyhow::Result<(i32, i32)> {
|
||||||
let imp = imp::IvImageView::from_instance(&self);
|
let imp = imp::IvImageView::from_instance(&self);
|
||||||
|
|
||||||
if let Some(current_file) = imp.picture.file() {
|
if let Some(current_file) = imp.picture.file() {
|
||||||
if current_file.path().as_deref() == file.path().as_deref() {
|
if current_file.path().as_deref() == file.path().as_deref() {
|
||||||
return;
|
return Err(anyhow::Error::msg(
|
||||||
|
"Image is the same as the previous image; Doing nothing.",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_parent_from_file(file);
|
self.set_parent_from_file(file);
|
||||||
imp.picture.set_file(Some(file));
|
let texture = gdk::Texture::from_file(file)?;
|
||||||
|
imp.picture.set_paintable(Some(&texture));
|
||||||
|
*imp.uri.borrow_mut() = Some(file.uri().to_string());
|
||||||
self.notify("filename");
|
self.notify("filename");
|
||||||
self.update_action_state();
|
self.update_action_state();
|
||||||
|
|
||||||
if let Err(e) = self.load_dimensions_from_file(file) {
|
log::debug!(
|
||||||
log::error!("Could not load image dimensions: {}", e);
|
"Image dimensions: {} x {}",
|
||||||
};
|
texture.width(),
|
||||||
|
texture.height()
|
||||||
|
);
|
||||||
|
Ok((texture.width(), texture.height()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_parent_from_file(&self, file: &gio::File) {
|
fn set_parent_from_file(&self, file: &gio::File) {
|
||||||
|
|
@ -251,17 +238,6 @@ impl IvImageView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_dimensions_from_file(&self, file: &gio::File) -> anyhow::Result<()> {
|
|
||||||
let pb = file.path().context("No path for current file")?;
|
|
||||||
let (_, width, height) =
|
|
||||||
gdk_pixbuf::Pixbuf::file_info(&pb.as_path()).context("Could not get file info")?;
|
|
||||||
|
|
||||||
log::debug!("Image dimensions: {} x {}", width, height);
|
|
||||||
let _ = self.emit_by_name("dimensions-loaded", &[&width, &height]);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_image(&self) {
|
fn update_image(&self) {
|
||||||
let imp = imp::IvImageView::from_instance(&self);
|
let imp = imp::IvImageView::from_instance(&self);
|
||||||
|
|
||||||
|
|
@ -270,8 +246,10 @@ impl IvImageView {
|
||||||
imp.directory.borrow().as_ref().unwrap(),
|
imp.directory.borrow().as_ref().unwrap(),
|
||||||
&imp.directory_pictures.borrow()[imp.index.get()]
|
&imp.directory_pictures.borrow()[imp.index.get()]
|
||||||
);
|
);
|
||||||
|
|
||||||
let file = gio::File::for_path(path);
|
let file = gio::File::for_path(path);
|
||||||
imp.picture.set_file(Some(&file));
|
imp.picture.set_file(Some(&file));
|
||||||
|
*imp.uri.borrow_mut() = Some(file.uri().to_string());
|
||||||
*imp.filename.borrow_mut() = util::get_file_display_name(&file);
|
*imp.filename.borrow_mut() = util::get_file_display_name(&file);
|
||||||
self.notify("filename");
|
self.notify("filename");
|
||||||
self.update_action_state();
|
self.update_action_state();
|
||||||
|
|
@ -311,9 +289,12 @@ impl IvImageView {
|
||||||
pub fn print(&self) -> anyhow::Result<()> {
|
pub fn print(&self) -> anyhow::Result<()> {
|
||||||
let imp = imp::IvImageView::from_instance(&self);
|
let imp = imp::IvImageView::from_instance(&self);
|
||||||
|
|
||||||
let file = imp.picture.file().context("No file to print")?;
|
|
||||||
let operation = gtk::PrintOperation::new();
|
let operation = gtk::PrintOperation::new();
|
||||||
let path = file.path().context("No path for current file")?;
|
let path = &format!(
|
||||||
|
"{}/{}",
|
||||||
|
imp.directory.borrow().as_ref().unwrap(),
|
||||||
|
&imp.directory_pictures.borrow()[imp.index.get()]
|
||||||
|
);
|
||||||
let pb = gdk_pixbuf::Pixbuf::from_file(path)?;
|
let pb = gdk_pixbuf::Pixbuf::from_file(path)?;
|
||||||
|
|
||||||
let setup = gtk::PageSetup::default();
|
let setup = gtk::PageSetup::default();
|
||||||
|
|
@ -346,8 +327,7 @@ impl IvImageView {
|
||||||
|
|
||||||
pub fn uri(&self) -> Option<String> {
|
pub fn uri(&self) -> Option<String> {
|
||||||
let imp = imp::IvImageView::from_instance(&self);
|
let imp = imp::IvImageView::from_instance(&self);
|
||||||
let file = imp.picture.file()?;
|
imp.uri.borrow().to_owned()
|
||||||
Some(file.uri().to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filename(&self) -> Option<String> {
|
pub fn filename(&self) -> Option<String> {
|
||||||
|
|
@ -368,22 +348,6 @@ impl IvImageView {
|
||||||
imp.popover.set_pointing_to(&rect);
|
imp.popover.set_pointing_to(&rect);
|
||||||
imp.popover.popup();
|
imp.popover.popup();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_dimensions_loaded<F: Fn(&Self, i32, i32) + 'static>(
|
|
||||||
&self,
|
|
||||||
f: F,
|
|
||||||
) -> glib::SignalHandlerId {
|
|
||||||
self.connect_local("dimensions-loaded", true, move |values| {
|
|
||||||
let view = values[0].get::<Self>().unwrap();
|
|
||||||
let width = values[1].get::<i32>().unwrap();
|
|
||||||
let height = values[2].get::<i32>().unwrap();
|
|
||||||
|
|
||||||
f(&view, width, height);
|
|
||||||
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_wallpaper(uri: String) {
|
async fn set_wallpaper(uri: String) {
|
||||||
|
|
|
||||||
|
|
@ -134,12 +134,6 @@ mod imp {
|
||||||
obj.pick_file();
|
obj.pick_file();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.image_view.connect_dimensions_loaded(
|
|
||||||
clone!(@weak obj => move |_, width, height| {
|
|
||||||
obj.resize_from_dimensions(width, height);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Property bindings didn't seem to work here
|
// Property bindings didn't seem to work here
|
||||||
self.image_view.connect_notify_local(
|
self.image_view.connect_notify_local(
|
||||||
Some("filename"),
|
Some("filename"),
|
||||||
|
|
@ -259,12 +253,15 @@ impl IvWindow {
|
||||||
let imp = imp::IvWindow::from_instance(self);
|
let imp = imp::IvWindow::from_instance(self);
|
||||||
|
|
||||||
log::debug!("Loading file: {}", file.uri().to_string());
|
log::debug!("Loading file: {}", file.uri().to_string());
|
||||||
|
match imp.image_view.set_image_from_file(file) {
|
||||||
imp.image_view.set_image_from_file(file);
|
Ok((width, height)) => {
|
||||||
imp.stack.set_visible_child(&*imp.image_view);
|
self.resize_from_dimensions(width, height);
|
||||||
imp.image_view.grab_focus();
|
imp.stack.set_visible_child(&*imp.image_view);
|
||||||
|
imp.image_view.grab_focus();
|
||||||
self.set_actions_enabled(true);
|
self.set_actions_enabled(true)
|
||||||
|
}
|
||||||
|
Err(e) => log::error!("Could not load file: {}", e.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_actions_enabled(&self, enabled: bool) {
|
pub fn set_actions_enabled(&self, enabled: bool) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue