Implement drag source on images
Using a 128x128 thumbnail.
This commit is contained in:
parent
fc6d3668c0
commit
13d7a21501
5 changed files with 135 additions and 0 deletions
|
|
@ -22,6 +22,7 @@ use gtk::gio::{self, prelude::*};
|
||||||
|
|
||||||
mod application;
|
mod application;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod thumbnail;
|
||||||
mod util;
|
mod util;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ rust_sources = files(
|
||||||
'config.rs',
|
'config.rs',
|
||||||
'main.rs',
|
'main.rs',
|
||||||
'util.rs',
|
'util.rs',
|
||||||
|
'thumbnail.rs',
|
||||||
'window.rs',
|
'window.rs',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
90
src/thumbnail.rs
Normal file
90
src/thumbnail.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use gtk::{gdk, glib};
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
const SIZE: i32 = 128;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Thumbnail {
|
||||||
|
pub image: OnceCell<gdk::Paintable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for Thumbnail {
|
||||||
|
const NAME: &'static str = "Thumbnail";
|
||||||
|
type Type = super::Thumbnail;
|
||||||
|
type ParentType = glib::Object;
|
||||||
|
type Interfaces = (gdk::Paintable,);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for Thumbnail {}
|
||||||
|
impl PaintableImpl for Thumbnail {
|
||||||
|
fn intrinsic_height(&self, _paintable: &Self::Type) -> i32 {
|
||||||
|
let image = self.image.get().unwrap();
|
||||||
|
let width = image.intrinsic_width();
|
||||||
|
let height = image.intrinsic_height();
|
||||||
|
let aspect_ratio = width as f64 / (height as f64).max(std::f64::EPSILON);
|
||||||
|
|
||||||
|
if width >= height {
|
||||||
|
(SIZE as f64 / aspect_ratio) as i32
|
||||||
|
} else {
|
||||||
|
SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intrinsic_width(&self, _paintable: &Self::Type) -> i32 {
|
||||||
|
let image = self.image.get().unwrap();
|
||||||
|
let width = image.intrinsic_width();
|
||||||
|
let height = image.intrinsic_height();
|
||||||
|
let aspect_ratio = width as f64 / (height as f64).max(std::f64::EPSILON);
|
||||||
|
|
||||||
|
if width >= height {
|
||||||
|
SIZE
|
||||||
|
} else {
|
||||||
|
(SIZE as f64 * aspect_ratio) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intrinsic_aspect_ratio(&self, _paintable: &Self::Type) -> f64 {
|
||||||
|
self.image.get().unwrap().intrinsic_aspect_ratio()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(
|
||||||
|
&self,
|
||||||
|
paintable: &Self::Type,
|
||||||
|
snapshot: &gdk::Snapshot,
|
||||||
|
_width: f64,
|
||||||
|
_height: f64,
|
||||||
|
) {
|
||||||
|
let width = paintable.intrinsic_width() as f64;
|
||||||
|
let height = paintable.intrinsic_height() as f64;
|
||||||
|
|
||||||
|
self.image.get().unwrap().snapshot(snapshot, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
/// Thumbnail Paintable
|
||||||
|
///
|
||||||
|
/// Creates a thumbnail from another paintable. The thumbnail will be drawn
|
||||||
|
/// at a maximum size of 128 × 128 taking into account the original
|
||||||
|
/// paintable aspect ratio.
|
||||||
|
pub struct Thumbnail(ObjectSubclass<imp::Thumbnail>) @implements gdk::Paintable;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Thumbnail {
|
||||||
|
pub fn new(paintable: &impl glib::IsA<gdk::Paintable>) -> Self {
|
||||||
|
let object = glib::Object::new::<Self>(&[]).unwrap();
|
||||||
|
let imp = object.imp();
|
||||||
|
|
||||||
|
imp.image.set(paintable.clone().upcast()).unwrap();
|
||||||
|
|
||||||
|
object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -210,4 +210,22 @@ impl LpImage {
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
imp.texture.borrow().clone()
|
imp.texture.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn content_provider(&self) -> anyhow::Result<gdk::ContentProvider> {
|
||||||
|
let imp = self.imp();
|
||||||
|
let mut contents = vec![];
|
||||||
|
|
||||||
|
if let Some(file) = imp.file.borrow().as_ref() {
|
||||||
|
let content = gdk::ContentProvider::for_value(&file.to_value());
|
||||||
|
contents.push(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(texture) = imp.texture.borrow().as_ref() {
|
||||||
|
let bytes = texture.save_to_png_bytes();
|
||||||
|
let content = gdk::ContentProvider::for_bytes("image/png", &bytes);
|
||||||
|
contents.push(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(gdk::ContentProvider::new_union(contents.as_slice()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ use ashpd::WindowIdentifier;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
|
use crate::thumbnail::Thumbnail;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::widgets::LpImage;
|
use crate::widgets::LpImage;
|
||||||
|
|
||||||
|
|
@ -131,6 +132,30 @@ mod imp {
|
||||||
.connect_pressed(clone!(@weak obj => move |_, x, y| {
|
.connect_pressed(clone!(@weak obj => move |_, x, y| {
|
||||||
obj.show_popover_at(x, y);
|
obj.show_popover_at(x, y);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let source = gtk::DragSource::new();
|
||||||
|
|
||||||
|
source.connect_prepare(
|
||||||
|
glib::clone!(@weak obj => @default-return None, move |_, _, _| {
|
||||||
|
match obj.imp().picture.content_provider() {
|
||||||
|
Ok(content) => Some(content),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not get content provider: {:?}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
source.connect_drag_begin(glib::clone!(@weak obj => move |source, _| {
|
||||||
|
let imp = obj.imp();
|
||||||
|
if let Some(texture) = imp.picture.texture() {
|
||||||
|
let thumbnail = Thumbnail::new(&texture);
|
||||||
|
source.set_icon(Some(&thumbnail), 0, 0);
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
obj.add_controller(&source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue