print: Make preview size adaptive

Part-of: <https://gitlab.gnome.org/GNOME/loupe/-/merge_requests/240>
This commit is contained in:
Sophie Herold 2023-06-26 15:35:16 +02:00 • committed by Christopher Davis
parent 65af818567
commit e6646bdbe3
3 changed files with 127 additions and 73 deletions

View file

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<template class="LpPrint" parent="AdwWindow"> <template class="LpPrint" parent="AdwWindow">
<property name="default-width">600</property> <property name="default-width">900</property>
<property name="default-height">650</property>
<signal name="notify::orientation" handler="orientation_changed" swapped="yes" /> <signal name="notify::orientation" handler="orientation_changed" swapped="yes" />
<child> <child>
<object class="GtkShortcutController"> <object class="GtkShortcutController">
@ -42,9 +43,8 @@
</object> </object>
</child> </child>
<property name="content"> <property name="content">
<object class="GtkBox"> <object class="AdwOverlaySplitView">
<property name="orientation">horizontal</property> <property name="sidebar">
<child>
<object class="AdwPreferencesPage"> <object class="AdwPreferencesPage">
<property name="halign">start</property> <property name="halign">start</property>
<property name="width-request">300</property> <property name="width-request">300</property>
@ -151,17 +151,18 @@
</object> </object>
</child> </child>
</object> </object>
</child> </property>
<child> <property name="content">
<object class="LpPrintPreview" id="preview"> <object class="LpPrintPreview" id="preview">
<property name="valign">center</property> <property name="vexpand">true</property>
<property name="halign">center</property> <property name="hexpand">true</property>
<property name="css-name">lpprintpreview</property> <property name="width-request">260</property>
<property name="height-request">260</property>
<binding name="print"> <binding name="print">
<constant>LpPrint</constant> <constant>LpPrint</constant>
</binding> </binding>
</object> </object>
</child> </property>
</object> </object>
</property> </property>
</object> </object>

View file

@ -46,7 +46,11 @@ row.property label.subtitle {
} }
lpprintpreview { lpprintpreview {
background-color: rgb(240, 240, 240); background-color: #858585;
border-radius: 4px; padding: 30px;
box-shadow: 0 0 14px 1px black; }
lpprintpreviewpage {
background-color: #f0f0f0;
box-shadow: 0 0 14px 3px #666;
} }

View file

@ -25,64 +25,39 @@ use glib::Properties;
use gtk::prelude::*; use gtk::prelude::*;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
mod imp { mod imp_page {
use super::*; use super::*;
#[derive(Debug, Default, Properties)] #[derive(Debug, Default)]
#[properties(wrapper_type = super::LpPrintPreview)] pub struct LpPrintPreviewPage {}
pub struct LpPrintPreview {
#[property(get, set)]
print: OnceCell<LpPrint>,
}
#[glib::object_subclass] #[glib::object_subclass]
impl ObjectSubclass for LpPrintPreview { impl ObjectSubclass for LpPrintPreviewPage {
const NAME: &'static str = "LpPrintPreview"; const NAME: &'static str = "LpPrintPreviewPage";
type Type = super::LpPrintPreview; type Type = super::LpPrintPreviewPage;
type ParentType = gtk::Widget; type ParentType = gtk::Widget;
fn class_init(klass: &mut Self::Class) {
klass.set_css_name("lpprintpreviewpage")
}
} }
impl ObjectImpl for LpPrintPreview { impl ObjectImpl for LpPrintPreviewPage {
fn constructed(&self) { fn constructed(&self) {
self.parent_constructed(); self.parent_constructed();
self.obj().set_halign(gtk::Align::Center);
self.obj().set_valign(gtk::Align::Start);
self.obj().set_overflow(gtk::Overflow::Hidden); self.obj().set_overflow(gtk::Overflow::Hidden);
} }
fn properties() -> &'static [glib::ParamSpec] {
Self::derived_properties()
}
fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
self.derived_set_property(id, value, pspec)
}
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
} }
impl WidgetImpl for LpPrintPreview { impl WidgetImpl for LpPrintPreviewPage {
fn measure(&self, orientation: gtk::Orientation, _for_size: i32) -> (i32, i32, i32, i32) {
let (width, height) = self.display_paper_dimensions();
let size = match orientation {
gtk::Orientation::Horizontal => width,
_ => height,
};
(size, size, -1, -1)
}
fn snapshot(&self, snapshot: &gtk::Snapshot) { fn snapshot(&self, snapshot: &gtk::Snapshot) {
let obj = self.obj();
snapshot.save(); snapshot.save();
let scale = obj.print().user_scale() * self.display_scale(); let scale = self.print().user_scale() * self.display_scale();
let margin_left = obj.print().effective_margin_left() * self.display_scale(); let margin_left = self.print().effective_margin_left() * self.display_scale();
let margin_top = obj.print().effective_margin_top() * self.display_scale(); let margin_top = self.print().effective_margin_top() * self.display_scale();
if let Some(texture) = self.obj().print().image().print_data(scale) { if let Some(texture) = self.print().image().print_data(scale) {
let area = graphene::Rect::new( let area = graphene::Rect::new(
margin_left as f32, margin_left as f32,
margin_top as f32, margin_top as f32,
@ -106,34 +81,108 @@ mod imp {
} }
} }
impl LpPrintPreview { impl LpPrintPreviewPage {
/// Returns scale factor from print pixel to preview size fn preview(&self) -> super::LpPrintPreview {
fn display_scale(&self) -> f64 { self.obj().parent().unwrap().downcast().unwrap()
let print = self.obj().print();
let height = print.page_setup().paper_height(gtk::Unit::Inch) * print.dpi();
let width = print.page_setup().paper_width(gtk::Unit::Inch) * print.dpi();
300. / f64::max(width, height)
} }
/// Returns total preview size in pixels fn print(&self) -> LpPrint {
fn display_paper_dimensions(&self) -> (i32, i32) { self.preview().print()
}
fn display_scale(&self) -> f64 {
let print = self.print();
let page_width = print.page_setup().paper_width(gtk::Unit::Inch) * print.dpi();
self.obj().width() as f64 / page_width
}
}
}
mod imp {
use super::*;
#[derive(Debug, Default, Properties)]
#[properties(wrapper_type = super::LpPrintPreview)]
pub struct LpPrintPreview {
#[property(get, set)]
print: OnceCell<LpPrint>,
page: LpPrintPreviewPage,
}
#[glib::object_subclass]
impl ObjectSubclass for LpPrintPreview {
const NAME: &'static str = "LpPrintPreview";
type Type = super::LpPrintPreview;
type ParentType = gtk::Widget;
fn class_init(klass: &mut Self::Class) {
klass.set_css_name("lpprintpreview")
}
}
impl ObjectImpl for LpPrintPreview {
fn constructed(&self) {
self.parent_constructed();
self.page.insert_after(&*self.obj(), gtk::Widget::NONE);
}
fn properties() -> &'static [glib::ParamSpec] {
Self::derived_properties()
}
fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
self.derived_set_property(id, value, pspec)
}
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
impl WidgetImpl for LpPrintPreview {
fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
let (page_width, page_height) = self.aspect_preserving_size(width, height);
self.page.size_allocate(
&gdk::Rectangle::new(
(width - page_width) / 2,
(height - page_height) / 2,
page_width,
page_height,
),
baseline,
);
self.page.queue_draw();
}
}
impl LpPrintPreview {
fn aspect_preserving_size(&self, for_width: i32, for_height: i32) -> (i32, i32) {
let print = self.obj().print(); let print = self.obj().print();
let height = print.page_setup().paper_height(gtk::Unit::Inch) * print.dpi(); let ratio = (print.page_setup().paper_width(gtk::Unit::Inch)
let width = print.page_setup().paper_width(gtk::Unit::Inch) * print.dpi(); / print.page_setup().paper_height(gtk::Unit::Inch)) as f32;
let scale = self.display_scale(); if ratio > for_width as f32 / for_height as f32 {
(for_width, (for_width as f32 / ratio) as i32)
((width * scale) as i32, (height * scale) as i32) } else {
((for_height as f32 * ratio) as i32, for_height)
}
} }
} }
} }
glib::wrapper! { glib::wrapper! {
pub struct LpPrintPreview(ObjectSubclass<imp::LpPrintPreview>) pub struct LpPrintPreviewPage(ObjectSubclass<imp_page::LpPrintPreviewPage>)
@extends gtk::Widget; @extends gtk::Widget;
} }
#[gtk::template_callbacks] impl Default for LpPrintPreviewPage {
impl LpPrintPreview {} fn default() -> Self {
glib::Object::new()
}
}
glib::wrapper! {
pub struct LpPrintPreview(ObjectSubclass<imp::LpPrintPreview>)
@extends gtk::Widget;
}