window: Implement drag and drop
The main page is no longer a lie.
This commit is contained in:
parent
5d9567507c
commit
be70bdafe5
5 changed files with 67 additions and 11 deletions
|
|
@ -20,6 +20,7 @@ features = ["feature_gtk4"]
|
||||||
[dependencies.gtk]
|
[dependencies.gtk]
|
||||||
package = "gtk4"
|
package = "gtk4"
|
||||||
git = "https://github.com/gtk-rs/gtk4-rs"
|
git = "https://github.com/gtk-rs/gtk4-rs"
|
||||||
|
features = ["v4_6"]
|
||||||
|
|
||||||
[dependencies.adw]
|
[dependencies.adw]
|
||||||
package = "libadwaita"
|
package = "libadwaita"
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,11 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="LpImageView" id="image_view"/>
|
<object class="LpImageView" id="image_view"/>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkDropTarget" id="drop_target">
|
||||||
|
<property name="actions">copy</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</property>
|
</property>
|
||||||
<style>
|
<style>
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ mod imp {
|
||||||
fn open(&self, application: &Self::Type, files: &[gio::File], _hint: &str) {
|
fn open(&self, application: &Self::Type, files: &[gio::File], _hint: &str) {
|
||||||
for file in files {
|
for file in files {
|
||||||
let win = LpWindow::new(application);
|
let win = LpWindow::new(application);
|
||||||
win.set_image_from_file(file);
|
win.set_image_from_file(file, true);
|
||||||
win.show();
|
win.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
src/util.rs
25
src/util.rs
|
|
@ -13,13 +13,24 @@ pub fn utf8_collate_key_for_filename(filename: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_display_name(file: &gio::File) -> Option<String> {
|
pub fn get_file_display_name(file: &gio::File) -> Option<String> {
|
||||||
let info = file
|
let info = query_attributes(file, vec![&gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME]).ok()?;
|
||||||
.query_info(
|
|
||||||
*gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
|
|
||||||
gio::FileQueryInfoFlags::empty(),
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
)
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
Some(info.display_name().to_string())
|
Some(info.display_name().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn query_attributes(
|
||||||
|
file: &gio::File,
|
||||||
|
attributes: Vec<&str>,
|
||||||
|
) -> Result<gio::FileInfo, glib::Error> {
|
||||||
|
let mut attributes = attributes;
|
||||||
|
let mut attr_str = String::from(attributes.remove(0));
|
||||||
|
for attr in attributes {
|
||||||
|
attr_str.push_str(&format!(",{}", attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
file.query_info(
|
||||||
|
&attr_str,
|
||||||
|
gio::FileQueryInfoFlags::empty(),
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ use gtk::subclass::prelude::*;
|
||||||
use gtk::CompositeTemplate;
|
use gtk::CompositeTemplate;
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
use crate::util;
|
||||||
use crate::widgets::LpImageView;
|
use crate::widgets::LpImageView;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -65,6 +66,8 @@ mod imp {
|
||||||
pub status_page: TemplateChild<adw::StatusPage>,
|
pub status_page: TemplateChild<adw::StatusPage>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub image_view: TemplateChild<LpImageView>,
|
pub image_view: TemplateChild<LpImageView>,
|
||||||
|
#[template_child]
|
||||||
|
pub drop_target: TemplateChild<gtk::DropTarget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -135,6 +138,39 @@ mod imp {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.drop_target.set_types(&[gdk::FileList::static_type()]);
|
||||||
|
self.drop_target.connect_drop(
|
||||||
|
clone!(@weak obj => @default-return false, move |_, value, _, _| {
|
||||||
|
// Here we use a GValue, which is a dynamic object that can hold different types,
|
||||||
|
// e.g. strings, numbers, or in this case objects. In order to get the GdkFileList
|
||||||
|
// from the GValue, we need to use the `get()` method.
|
||||||
|
//
|
||||||
|
// We've added type annotations here, and written it as `let list: gdk::FileList = ...`,
|
||||||
|
// but you might also see places where type arguments are used.
|
||||||
|
// This line could have been written as `let list = value.get::<gdk::FileList>().unwrap()`.
|
||||||
|
let list: gdk::FileList = value.get().unwrap();
|
||||||
|
|
||||||
|
// TODO: Handle this like EOG and make a "directory" out of the given files
|
||||||
|
let file = list.files().get(0).unwrap().clone();
|
||||||
|
let info = util::query_attributes(
|
||||||
|
&file,
|
||||||
|
vec![&gio::FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE])
|
||||||
|
.expect("Could not query file info");
|
||||||
|
|
||||||
|
if info
|
||||||
|
.content_type()
|
||||||
|
.map(|t| t.to_string())
|
||||||
|
.filter(|t| t.starts_with("image/"))
|
||||||
|
.is_some() {
|
||||||
|
obj.set_image_from_file(&file, false);
|
||||||
|
} else {
|
||||||
|
log::debug!("{} was not a valid image.", file.uri().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +237,7 @@ impl LpWindow {
|
||||||
clone!(@weak self as win, @strong chooser => move |_, resp| {
|
clone!(@weak self as win, @strong chooser => move |_, resp| {
|
||||||
if resp == gtk::ResponseType::Accept {
|
if resp == gtk::ResponseType::Accept {
|
||||||
if let Some(file) = chooser.file() {
|
if let Some(file) = chooser.file() {
|
||||||
win.set_image_from_file(&file);
|
win.set_image_from_file(&file, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
@ -239,13 +275,16 @@ impl LpWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_image_from_file(&self, file: &gio::File) {
|
pub fn set_image_from_file(&self, file: &gio::File, resize: bool) {
|
||||||
let imp = imp::LpWindow::from_instance(self);
|
let imp = imp::LpWindow::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) {
|
match imp.image_view.set_image_from_file(file) {
|
||||||
Ok((width, height)) => {
|
Ok((width, height)) => {
|
||||||
|
if resize {
|
||||||
self.resize_from_dimensions(width, height);
|
self.resize_from_dimensions(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
imp.stack.set_visible_child(&*imp.image_view);
|
imp.stack.set_visible_child(&*imp.image_view);
|
||||||
imp.image_view.grab_focus();
|
imp.image_view.grab_focus();
|
||||||
self.set_actions_enabled(true)
|
self.set_actions_enabled(true)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue