print: Use LpImage for preview
This commit is contained in:
parent
e387d8dc66
commit
6827a9c176
9 changed files with 143 additions and 44 deletions
|
|
@ -117,6 +117,13 @@ const MAX_ZOOM_LEVEL: f64 = 20.0;
|
|||
/// The thumbnail is currently used for drag and drop.
|
||||
const THUMBNAIL_SIZE: f32 = 128.;
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub enum FitMode {
|
||||
#[default]
|
||||
BestFit,
|
||||
LargeFit,
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
|
|
@ -134,8 +141,10 @@ mod imp {
|
|||
/// Set if an error has occurred, shown on error_page
|
||||
#[property(get)]
|
||||
pub(super) error: RefCell<Option<String>>,
|
||||
//pub(super) format: RefCell<Option<decoder::ImageFormat>>,
|
||||
pub(super) background_color: RefCell<Option<gdk::RGBA>>,
|
||||
pub(super) fixed_background_color: RefCell<Option<gdk::RGBA>>,
|
||||
/// Animations disabled
|
||||
pub(super) still: Cell<bool>,
|
||||
|
||||
/// Track changes to this image
|
||||
pub(super) file_monitor: RefCell<Option<gio::FileMonitor>>,
|
||||
|
|
@ -170,6 +179,8 @@ mod imp {
|
|||
/// Always fit image into window, causes `zoom` to change automatically
|
||||
#[property(get, set)]
|
||||
pub(super) best_fit: Cell<bool>,
|
||||
/// Determines what `best-fit` does
|
||||
pub(super) fit_mode: Cell<FitMode>,
|
||||
/// Max zoom level is reached, stored to only send signals on change
|
||||
#[property(get, set)]
|
||||
pub(super) is_max_zoom: Cell<bool>,
|
||||
|
|
@ -224,6 +235,10 @@ mod imp {
|
|||
type ParentType = gtk::Widget;
|
||||
type Type = super::LpImage;
|
||||
type Interfaces = (gtk::Scrollable,);
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.set_css_name("lpimage")
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for LpImage {
|
||||
|
|
@ -310,3 +325,16 @@ glib::wrapper! {
|
|||
@extends gtk::Widget,
|
||||
@implements gtk::Scrollable;
|
||||
}
|
||||
|
||||
impl LpImage {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
|
||||
/// Rerturns new not animated image
|
||||
pub fn new_still() -> Self {
|
||||
let image = Self::new();
|
||||
image.imp().still.replace(true);
|
||||
image
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,20 @@ impl LpImage {
|
|||
///
|
||||
/// Returns the default color if no one has been guessed yet
|
||||
pub fn background_color(&self) -> gdk::RGBA {
|
||||
(*self.imp().background_color.borrow()).unwrap_or_else(Self::default_background_color)
|
||||
let imp = self.imp();
|
||||
|
||||
if let Some(fixed) = *imp.fixed_background_color.borrow() {
|
||||
return fixed;
|
||||
}
|
||||
|
||||
(*imp.background_color.borrow()).unwrap_or_else(Self::default_background_color)
|
||||
}
|
||||
|
||||
pub fn set_background_color(&self, color: Option<gdk::RGBA>) {
|
||||
pub fn set_fixed_background_color(&self, color: Option<gdk::RGBA>) {
|
||||
self.imp().fixed_background_color.replace(color);
|
||||
}
|
||||
|
||||
pub(super) fn set_background_color(&self, color: Option<gdk::RGBA>) {
|
||||
self.imp().background_color.replace(color);
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +61,12 @@ impl LpImage {
|
|||
/// For non-transparent images this always returns
|
||||
/// `BACKGROUND_COLOR_DEFAULT`
|
||||
pub async fn background_color_guess(&self) -> Option<gdk::RGBA> {
|
||||
let imp = self.imp();
|
||||
|
||||
if imp.fixed_background_color.borrow().is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Shortcut for formats that don't support transparency
|
||||
if !self
|
||||
.metadata()
|
||||
|
|
|
|||
|
|
@ -146,9 +146,14 @@ impl LpImage {
|
|||
self.emmit_metadata_changed();
|
||||
}
|
||||
DecoderUpdate::Animated => {
|
||||
let callback_id = self
|
||||
if imp.still.get() {
|
||||
// Just load the first frame
|
||||
self.imp().frame_buffer.next_frame();
|
||||
} else {
|
||||
let callback_id = self
|
||||
.add_tick_callback(glib::clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move |_, clock| obj.tick_callback(clock)));
|
||||
imp.tick_callback.replace(Some(callback_id));
|
||||
imp.tick_callback.replace(Some(callback_id));
|
||||
}
|
||||
}
|
||||
DecoderUpdate::UnsupportedFormat => {
|
||||
self.set_unsupported(true);
|
||||
|
|
|
|||
|
|
@ -49,16 +49,23 @@ impl LpImage {
|
|||
let texture_aspect_ratio = image_width / image_height;
|
||||
let widget_aspect_ratio = self.width() as f64 / self.height() as f64;
|
||||
|
||||
let max_zoom_factor = match self.imp().fit_mode.get() {
|
||||
// Do not allow to zoom larger than original size
|
||||
FitMode::BestFit => 1.,
|
||||
// Allow arbitrary zoom
|
||||
FitMode::LargeFit => f64::MAX,
|
||||
};
|
||||
|
||||
let default_zoom = if texture_aspect_ratio > widget_aspect_ratio {
|
||||
(self.width() as f64 / image_width).min(1.)
|
||||
(self.width() as f64 / image_width).min(max_zoom_factor)
|
||||
} else {
|
||||
(self.height() as f64 / image_height).min(1.)
|
||||
(self.height() as f64 / image_height).min(max_zoom_factor)
|
||||
};
|
||||
|
||||
let rotated_zoom = if 1. / texture_aspect_ratio > widget_aspect_ratio {
|
||||
(self.width() as f64 / image_height).min(1.)
|
||||
(self.width() as f64 / image_height).min(max_zoom_factor)
|
||||
} else {
|
||||
(self.height() as f64 / image_width).min(1.)
|
||||
(self.height() as f64 / image_width).min(max_zoom_factor)
|
||||
};
|
||||
|
||||
rotated * rotated_zoom + (1. - rotated) * default_zoom
|
||||
|
|
@ -80,6 +87,11 @@ impl LpImage {
|
|||
self.imp().best_fit.get()
|
||||
}
|
||||
|
||||
pub fn set_fit_mode(&self, fit_mode: FitMode) {
|
||||
self.imp().fit_mode.replace(fit_mode);
|
||||
self.configure_best_fit();
|
||||
}
|
||||
|
||||
pub(super) fn applicable_zoom(&self) -> f64 {
|
||||
decoder::tiling::zoom_normalize(self.zoom()) / self.scaling()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -479,11 +479,15 @@ glib::wrapper! {
|
|||
|
||||
impl LpPrint {
|
||||
pub fn new(
|
||||
image: LpImage,
|
||||
image1: LpImage,
|
||||
parent_window: gtk::Window,
|
||||
print_settings: Option<gtk::PrintSettings>,
|
||||
page_setup: Option<gtk::PageSetup>,
|
||||
) -> Self {
|
||||
let image = LpImage::new_still();
|
||||
image.set_fixed_background_color(Some(gdk::RGBA::new(0.94, 0.94, 0.94, 1.)));
|
||||
let image2 = image.clone();
|
||||
glib::spawn_future_local(async move { image2.load(&image1.file().unwrap()).await });
|
||||
let print_settings = print_settings.unwrap_or_default();
|
||||
|
||||
let obj: Self = glib::Object::builder()
|
||||
|
|
|
|||
|
|
@ -17,14 +17,17 @@
|
|||
|
||||
//! Print preview widget that shows a fake page with the image on it
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::Properties;
|
||||
use gtk::prelude::*;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::deps::*;
|
||||
use crate::widgets::LpPrint;
|
||||
|
||||
use super::image;
|
||||
|
||||
mod imp_page {
|
||||
use super::*;
|
||||
|
||||
|
|
@ -47,42 +50,35 @@ mod imp_page {
|
|||
self.parent_constructed();
|
||||
self.obj().set_overflow(gtk::Overflow::Hidden);
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
self.obj().first_child().unwrap().unparent();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for LpPrintPreviewPage {
|
||||
fn snapshot(&self, snapshot: >k::Snapshot) {
|
||||
snapshot.save();
|
||||
|
||||
let scale = self.print().user_scale_original() * self.display_scale();
|
||||
fn size_allocate(&self, _width: i32, _height: i32, _baseline: i32) {
|
||||
let margin_left = self.print().effective_margin_left() * self.display_scale();
|
||||
let margin_top = self.print().effective_margin_top() * self.display_scale();
|
||||
let width = self.print().user_width() * self.display_scale();
|
||||
let height = self.print().user_height() * self.display_scale();
|
||||
|
||||
if let Some(texture) = self.print().image().print_data(scale) {
|
||||
let area = graphene::Rect::new(
|
||||
margin_left as f32,
|
||||
margin_top as f32,
|
||||
texture.width() as f32,
|
||||
texture.height() as f32,
|
||||
);
|
||||
let image = self.print().image();
|
||||
|
||||
snapshot.append_texture(&texture, &area);
|
||||
|
||||
// Border around image
|
||||
snapshot.append_inset_shadow(
|
||||
&gsk::RoundedRect::from_rect(area, 0.),
|
||||
&gdk::RGBA::new(0., 0., 0., 0.3),
|
||||
0.,
|
||||
0.,
|
||||
1.,
|
||||
0.,
|
||||
);
|
||||
}
|
||||
snapshot.restore();
|
||||
image.allocate(
|
||||
width as i32,
|
||||
height as i32,
|
||||
-1,
|
||||
Some(
|
||||
gsk::Transform::new()
|
||||
.translate(&graphene::Point::new(margin_left as f32, margin_top as f32)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl LpPrintPreviewPage {
|
||||
fn preview(&self) -> super::LpPrintPreview {
|
||||
pub(super) fn preview(&self) -> super::LpPrintPreview {
|
||||
self.obj().parent().unwrap().downcast().unwrap()
|
||||
}
|
||||
|
||||
|
|
@ -99,13 +95,14 @@ mod imp_page {
|
|||
}
|
||||
|
||||
mod imp {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, Properties)]
|
||||
#[properties(wrapper_type = super::LpPrintPreview)]
|
||||
pub struct LpPrintPreview {
|
||||
#[property(get, set)]
|
||||
print: OnceCell<LpPrint>,
|
||||
#[property(type = LpPrint, get, set = Self::set_print)]
|
||||
print: RefCell<Option<LpPrint>>,
|
||||
page: LpPrintPreviewPage,
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +124,10 @@ mod imp {
|
|||
self.page.insert_after(&*self.obj(), gtk::Widget::NONE);
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
self.page.unparent();
|
||||
}
|
||||
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
Self::derived_properties()
|
||||
}
|
||||
|
|
@ -152,11 +153,21 @@ mod imp {
|
|||
baseline,
|
||||
);
|
||||
|
||||
self.page.queue_draw();
|
||||
self.page.queue_resize();
|
||||
}
|
||||
}
|
||||
|
||||
impl LpPrintPreview {
|
||||
fn set_print(&self, print: LpPrint) {
|
||||
let page = self.page.clone();
|
||||
print.connect_image_notify(move |_| {
|
||||
page.init();
|
||||
});
|
||||
|
||||
self.print.replace(Some(print));
|
||||
self.obj().notify_print();
|
||||
}
|
||||
|
||||
fn aspect_preserving_size(&self, for_width: i32, for_height: i32) -> (i32, i32) {
|
||||
let print = self.obj().print();
|
||||
|
||||
|
|
@ -182,6 +193,17 @@ impl Default for LpPrintPreviewPage {
|
|||
}
|
||||
}
|
||||
|
||||
impl LpPrintPreviewPage {
|
||||
fn init(&self) {
|
||||
let imp = self.imp();
|
||||
let image = imp.preview().print().image();
|
||||
|
||||
image.set_sensitive(false);
|
||||
image.set_parent(self);
|
||||
image.set_fit_mode(image::FitMode::LargeFit);
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct LpPrintPreview(ObjectSubclass<imp::LpPrintPreview>)
|
||||
@extends gtk::Widget;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue