print: Split unit selection for margins and size
Part-of: <https://gitlab.gnome.org/GNOME/loupe/-/merge_requests/240>
This commit is contained in:
parent
e6646bdbe3
commit
d7a77ec498
3 changed files with 182 additions and 70 deletions
|
|
@ -101,6 +101,23 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwPreferencesGroup">
|
||||||
<property name="title" translatable="yes">Margins</property>
|
<property name="title" translatable="yes">Margins</property>
|
||||||
|
<property name="header-suffix">
|
||||||
|
<object class="GtkDropDown" id="margin_unit">
|
||||||
|
<property name="tooltip-text" translatable="yes">Margin units</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat"/>
|
||||||
|
</style>
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkStringList">
|
||||||
|
<items>
|
||||||
|
<item>cm</item>
|
||||||
|
<item>in</item>
|
||||||
|
<item>px</item>
|
||||||
|
</items>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwSpinRow" id="margin_horizontal">
|
<object class="AdwSpinRow" id="margin_horizontal">
|
||||||
<property name="title" translatable="yes">Horizontal</property>
|
<property name="title" translatable="yes">Horizontal</property>
|
||||||
|
|
@ -116,6 +133,24 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwPreferencesGroup">
|
||||||
<property name="title" translatable="yes">Image Size</property>
|
<property name="title" translatable="yes">Image Size</property>
|
||||||
|
<property name="header-suffix">
|
||||||
|
<object class="GtkDropDown" id="size_unit">
|
||||||
|
<property name="tooltip-text" translatable="yes">Image size units</property>"
|
||||||
|
<style>
|
||||||
|
<class name="flat"/>
|
||||||
|
</style>
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkStringList">
|
||||||
|
<items>
|
||||||
|
<item>cm</item>
|
||||||
|
<item>in</item>
|
||||||
|
<item>px</item>
|
||||||
|
<item>%</item>
|
||||||
|
</items>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwSpinRow" id="width">
|
<object class="AdwSpinRow" id="width">
|
||||||
<property name="title" translatable="yes">Width</property>
|
<property name="title" translatable="yes">Width</property>
|
||||||
|
|
@ -133,21 +168,6 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="AdwComboRow" id="unit">
|
|
||||||
<property name="title" translatable="yes">Length Unit</property>
|
|
||||||
<signal name="notify::selected-item" handler="unit_selected" swapped="yes" />
|
|
||||||
<property name="model">
|
|
||||||
<object class="GtkStringList">
|
|
||||||
<items>
|
|
||||||
<item>cm</item>
|
|
||||||
<item>in</item>
|
|
||||||
<item>px</item>
|
|
||||||
</items>
|
|
||||||
</object>
|
|
||||||
</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
||||||
|
|
@ -54,3 +54,7 @@ lpprintpreviewpage {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
box-shadow: 0 0 14px 3px #666;
|
box-shadow: 0 0 14px 3px #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dropdown.flat button:not(:hover) {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,60 @@ impl std::fmt::Display for PageAlignment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy)]
|
||||||
|
enum Unit {
|
||||||
|
Centimeter,
|
||||||
|
Inch,
|
||||||
|
#[default]
|
||||||
|
Pixel,
|
||||||
|
Percent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> From<T> for Unit {
|
||||||
|
fn from(s: T) -> Self {
|
||||||
|
match s.as_ref() {
|
||||||
|
"cm" => Self::Centimeter,
|
||||||
|
"in" => Self::Inch,
|
||||||
|
"px" => Self::Pixel,
|
||||||
|
"%" => Self::Percent,
|
||||||
|
unit => {
|
||||||
|
log::error!("Unknown unit '{unit}'");
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unit {
|
||||||
|
fn factor(&self, dpi: f64, total_size: i32) -> f64 {
|
||||||
|
match self {
|
||||||
|
Self::Centimeter => 2.54 / dpi,
|
||||||
|
Self::Inch => 1. / dpi,
|
||||||
|
Self::Pixel => 1.,
|
||||||
|
Self::Percent => 100. / total_size as f64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn digits(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Centimeter => 2,
|
||||||
|
Self::Inch => 2,
|
||||||
|
Self::Pixel => 0,
|
||||||
|
Self::Percent => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ceil(&self, num: f64) -> f64 {
|
||||||
|
let f = 10_f64.powi(self.digits() as i32);
|
||||||
|
(num * f).ceil() / f
|
||||||
|
}
|
||||||
|
|
||||||
|
fn floor(&self, num: f64) -> f64 {
|
||||||
|
let f = 10_f64.powi(self.digits() as i32);
|
||||||
|
(num * f).floor() / f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
@ -110,17 +164,25 @@ mod imp {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) alignment: TemplateChild<adw::ComboRow>,
|
pub(super) alignment: TemplateChild<adw::ComboRow>,
|
||||||
|
|
||||||
|
#[template_child]
|
||||||
|
pub(super) margin_unit: TemplateChild<gtk::DropDown>,
|
||||||
|
#[property(get, set)]
|
||||||
|
pub(super) margin_unit_factor: Cell<f64>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) margin_horizontal: TemplateChild<adw::SpinRow>,
|
pub(super) margin_horizontal: TemplateChild<adw::SpinRow>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) margin_vertical: TemplateChild<adw::SpinRow>,
|
pub(super) margin_vertical: TemplateChild<adw::SpinRow>,
|
||||||
|
|
||||||
|
#[template_child]
|
||||||
|
pub(super) size_unit: TemplateChild<gtk::DropDown>,
|
||||||
|
#[property(get, set)]
|
||||||
|
pub(super) width_unit_factor: Cell<f64>,
|
||||||
|
#[property(get, set)]
|
||||||
|
pub(super) height_unit_factor: Cell<f64>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) width: TemplateChild<adw::SpinRow>,
|
pub(super) width: TemplateChild<adw::SpinRow>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) scale: TemplateChild<gtk::Label>,
|
pub(super) scale: TemplateChild<gtk::Label>,
|
||||||
#[template_child]
|
|
||||||
pub(super) unit: TemplateChild<adw::ComboRow>,
|
|
||||||
|
|
||||||
#[property(get, set, builder().construct_only())]
|
#[property(get, set, builder().construct_only())]
|
||||||
pub(super) image: OnceCell<LpImage>,
|
pub(super) image: OnceCell<LpImage>,
|
||||||
|
|
@ -133,8 +195,6 @@ mod imp {
|
||||||
|
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub(super) orientation: RefCell<String>,
|
pub(super) orientation: RefCell<String>,
|
||||||
#[property(get, set)]
|
|
||||||
pub(super) unit_factor: Cell<f64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -169,7 +229,9 @@ mod imp {
|
||||||
|
|
||||||
let obj = self.obj();
|
let obj = self.obj();
|
||||||
|
|
||||||
obj.set_unit_factor(1.);
|
obj.set_width_unit_factor(1.);
|
||||||
|
obj.set_height_unit_factor(1.);
|
||||||
|
obj.set_margin_unit_factor(1.);
|
||||||
|
|
||||||
obj.set_transient_for(Some(&obj.parent_window()));
|
obj.set_transient_for(Some(&obj.parent_window()));
|
||||||
obj.set_modal(true);
|
obj.set_modal(true);
|
||||||
|
|
@ -177,6 +239,7 @@ mod imp {
|
||||||
self.alignment.connect_selected_notify(
|
self.alignment.connect_selected_notify(
|
||||||
glib::clone!(@weak obj => move |_| obj.on_margin_vertical_changed()),
|
glib::clone!(@weak obj => move |_| obj.on_margin_vertical_changed()),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.alignment
|
self.alignment
|
||||||
.set_expression(Some(gtk::ClosureExpression::new::<glib::GString>(
|
.set_expression(Some(gtk::ClosureExpression::new::<glib::GString>(
|
||||||
[] as [gtk::Expression; 0],
|
[] as [gtk::Expression; 0],
|
||||||
|
|
@ -185,13 +248,13 @@ mod imp {
|
||||||
),
|
),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
gtk::ClosureExpression::new::<glib::GString>(
|
self.margin_unit.connect_selected_notify(
|
||||||
[] as [gtk::Expression; 0],
|
glib::clone!(@weak obj => move |_| obj.on_margin_unit_changed()),
|
||||||
glib::closure!(
|
|
||||||
|s: gtk::StringObject| PageAlignment::from(s.string().as_str()).to_string()
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.size_unit.connect_selected_notify(
|
||||||
|
glib::clone!(@weak obj => move |_| obj.on_size_unit_changed()),
|
||||||
|
);
|
||||||
self.width
|
self.width
|
||||||
.connect_value_notify(glib::clone!(@weak obj => move |_| obj.on_width_changed()));
|
.connect_value_notify(glib::clone!(@weak obj => move |_| obj.on_width_changed()));
|
||||||
self.margin_horizontal.connect_value_notify(
|
self.margin_horizontal.connect_value_notify(
|
||||||
|
|
@ -228,7 +291,7 @@ mod imp {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
imp.title.set_title(&gettext_f(
|
imp.title.set_title(&gettext_f(
|
||||||
// Translators: {} is a placeholder for the filename
|
// Translators: {} is a placeholder for the filename
|
||||||
"Print {}",
|
"Print “{}”",
|
||||||
&[&basename],
|
&[&basename],
|
||||||
));
|
));
|
||||||
if let Some(printer) = operation.print_settings().and_then(|x| x.printer()) {
|
if let Some(printer) = operation.print_settings().and_then(|x| x.printer()) {
|
||||||
|
|
@ -245,10 +308,9 @@ mod imp {
|
||||||
obj.set_ranges();
|
obj.set_ranges();
|
||||||
|
|
||||||
imp.width.set_value(obj.image().image_size().0 as f64);
|
imp.width.set_value(obj.image().image_size().0 as f64);
|
||||||
// TODO: Select center
|
|
||||||
//obj.center_horizontally();
|
|
||||||
|
|
||||||
obj.unit_selected();
|
obj.on_margin_unit_changed();
|
||||||
|
obj.on_size_unit_changed();
|
||||||
|
|
||||||
imp.print_operation.cancel();
|
imp.print_operation.cancel();
|
||||||
|
|
||||||
|
|
@ -309,13 +371,26 @@ impl LpPrint {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unit(&self) -> glib::GString {
|
fn size_unit(&self) -> Unit {
|
||||||
self.imp()
|
Unit::from(
|
||||||
.unit
|
self.imp()
|
||||||
.selected_item()
|
.size_unit
|
||||||
.and_downcast::<gtk::StringObject>()
|
.selected_item()
|
||||||
.map(|x| x.string())
|
.and_downcast::<gtk::StringObject>()
|
||||||
.unwrap_or_default()
|
.map(|x| x.string())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn margin_unit(&self) -> Unit {
|
||||||
|
Unit::from(
|
||||||
|
self.imp()
|
||||||
|
.margin_unit
|
||||||
|
.selected_item()
|
||||||
|
.and_downcast::<gtk::StringObject>()
|
||||||
|
.map(|x| x.string())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dpi(&self) -> f64 {
|
pub fn dpi(&self) -> f64 {
|
||||||
|
|
@ -344,7 +419,7 @@ impl LpPrint {
|
||||||
|
|
||||||
/// Returns user selected image width in pixels
|
/// Returns user selected image width in pixels
|
||||||
pub fn user_width(&self) -> f64 {
|
pub fn user_width(&self) -> f64 {
|
||||||
f64::max(1., self.imp().width.value() / self.unit_factor())
|
f64::max(1., self.imp().width.value() / self.width_unit_factor())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_height(&self) -> f64 {
|
pub fn user_height(&self) -> f64 {
|
||||||
|
|
@ -366,7 +441,7 @@ impl LpPrint {
|
||||||
|
|
||||||
/// Returns user selected left margin in pixels
|
/// Returns user selected left margin in pixels
|
||||||
pub fn user_margin_horizontal(&self) -> f64 {
|
pub fn user_margin_horizontal(&self) -> f64 {
|
||||||
self.imp().margin_horizontal.value() / self.unit_factor()
|
self.imp().margin_horizontal.value() / self.margin_unit_factor()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effective_margin_left(&self) -> f64 {
|
pub fn effective_margin_left(&self) -> f64 {
|
||||||
|
|
@ -393,7 +468,7 @@ impl LpPrint {
|
||||||
|
|
||||||
/// Returns user selected top margin in pixels
|
/// Returns user selected top margin in pixels
|
||||||
pub fn user_margin_vertical(&self) -> f64 {
|
pub fn user_margin_vertical(&self) -> f64 {
|
||||||
self.imp().margin_vertical.value() / self.unit_factor()
|
self.imp().margin_vertical.value() / self.margin_unit_factor()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effective_margin_top(&self) -> f64 {
|
pub fn effective_margin_top(&self) -> f64 {
|
||||||
|
|
@ -415,25 +490,31 @@ impl LpPrint {
|
||||||
fn set_ranges(&self) {
|
fn set_ranges(&self) {
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
|
|
||||||
let max_height =
|
let size_unit = self.size_unit();
|
||||||
self.page_setup().page_height(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
let max_height = self.page_setup().page_height(gtk::Unit::Inch) * self.dpi();
|
||||||
|
let max_width = self.page_setup().page_width(gtk::Unit::Inch) * self.dpi();
|
||||||
let max_width =
|
imp.width.set_range(
|
||||||
self.page_setup().page_width(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
size_unit.ceil(self.width_unit_factor()),
|
||||||
imp.width.set_range(self.unit_factor(), max_width);
|
size_unit.floor(max_width * self.width_unit_factor()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let margin_unit = self.margin_unit();
|
||||||
let min_horizontal_margin = f64::max(
|
let min_horizontal_margin = f64::max(
|
||||||
self.page_setup().left_margin(gtk::Unit::Inch),
|
self.page_setup().left_margin(gtk::Unit::Inch),
|
||||||
self.page_setup().right_margin(gtk::Unit::Inch),
|
self.page_setup().right_margin(gtk::Unit::Inch),
|
||||||
) * self.dpi()
|
) * self.dpi()
|
||||||
* self.unit_factor();
|
* self.margin_unit_factor();
|
||||||
imp.margin_horizontal
|
imp.margin_horizontal.set_range(
|
||||||
.set_range(min_horizontal_margin, min_horizontal_margin + max_width);
|
margin_unit.ceil(min_horizontal_margin),
|
||||||
|
margin_unit.floor(min_horizontal_margin + max_width * self.margin_unit_factor()),
|
||||||
|
);
|
||||||
|
|
||||||
let min_vertical_margin =
|
let min_vertical_margin =
|
||||||
self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi() * self.margin_unit_factor();
|
||||||
imp.margin_vertical
|
imp.margin_vertical.set_range(
|
||||||
.set_range(min_vertical_margin, min_vertical_margin + max_height);
|
margin_unit.ceil(min_vertical_margin),
|
||||||
|
margin_unit.floor(min_vertical_margin + max_height * self.margin_unit_factor()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
@ -448,35 +529,42 @@ impl LpPrint {
|
||||||
self.draw_preview();
|
self.draw_preview();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
fn on_size_unit_changed(&self) {
|
||||||
pub fn unit_selected(&self) {
|
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
|
|
||||||
let (unit_factor, digits) = match self.unit().as_str() {
|
let (orig_width, orig_height) = self.image().image_size();
|
||||||
"cm" => (2.54 / self.dpi(), 2),
|
|
||||||
"in" => (1. / self.dpi(), 2),
|
|
||||||
"px" => (1., 0),
|
|
||||||
unit => {
|
|
||||||
log::error!("Unknown unit '{unit}'");
|
|
||||||
(1., 2)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let update_factor = unit_factor / self.unit_factor();
|
let unit = self.size_unit();
|
||||||
let width = imp.width.value() * update_factor;
|
let width_factor = unit.factor(self.dpi(), orig_width);
|
||||||
|
let height_factor = unit.factor(self.dpi(), orig_height);
|
||||||
|
|
||||||
|
let width = imp.width.value() * width_factor / self.width_unit_factor();
|
||||||
|
|
||||||
|
self.set_width_unit_factor(width_factor);
|
||||||
|
self.set_height_unit_factor(height_factor);
|
||||||
|
self.set_ranges();
|
||||||
|
|
||||||
|
imp.width.set_digits(unit.digits());
|
||||||
|
imp.width.set_value(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_margin_unit_changed(&self) {
|
||||||
|
let imp = self.imp();
|
||||||
|
|
||||||
|
let unit = self.margin_unit();
|
||||||
|
let unit_factor = unit.factor(self.dpi(), 1);
|
||||||
|
|
||||||
|
let update_factor = unit_factor / self.margin_unit_factor();
|
||||||
let margin_horizontal = imp.margin_horizontal.value() * update_factor;
|
let margin_horizontal = imp.margin_horizontal.value() * update_factor;
|
||||||
let margin_vertical = imp.margin_vertical.value() * update_factor;
|
let margin_vertical = imp.margin_vertical.value() * update_factor;
|
||||||
|
|
||||||
self.set_unit_factor(unit_factor);
|
self.set_margin_unit_factor(unit_factor);
|
||||||
self.set_ranges();
|
self.set_ranges();
|
||||||
|
|
||||||
imp.width.set_digits(digits);
|
imp.margin_horizontal.set_digits(unit.digits());
|
||||||
imp.width.set_value(width);
|
|
||||||
|
|
||||||
imp.margin_horizontal.set_digits(digits);
|
|
||||||
imp.margin_horizontal.set_value(margin_horizontal);
|
imp.margin_horizontal.set_value(margin_horizontal);
|
||||||
|
|
||||||
imp.margin_vertical.set_digits(digits);
|
imp.margin_vertical.set_digits(unit.digits());
|
||||||
imp.margin_vertical.set_value(margin_vertical);
|
imp.margin_vertical.set_value(margin_vertical);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue