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>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<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>
|
||||
<object class="AdwSpinRow" id="margin_horizontal">
|
||||
<property name="title" translatable="yes">Horizontal</property>
|
||||
|
|
@ -116,6 +133,24 @@
|
|||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<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>
|
||||
<object class="AdwSpinRow" id="width">
|
||||
<property name="title" translatable="yes">Width</property>
|
||||
|
|
@ -133,21 +168,6 @@
|
|||
</child>
|
||||
</object>
|
||||
</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>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -54,3 +54,7 @@ lpprintpreviewpage {
|
|||
background-color: #f0f0f0;
|
||||
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 {
|
||||
use super::*;
|
||||
|
||||
|
|
@ -110,17 +164,25 @@ mod imp {
|
|||
#[template_child]
|
||||
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]
|
||||
pub(super) margin_horizontal: TemplateChild<adw::SpinRow>,
|
||||
#[template_child]
|
||||
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]
|
||||
pub(super) width: TemplateChild<adw::SpinRow>,
|
||||
#[template_child]
|
||||
pub(super) scale: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub(super) unit: TemplateChild<adw::ComboRow>,
|
||||
|
||||
#[property(get, set, builder().construct_only())]
|
||||
pub(super) image: OnceCell<LpImage>,
|
||||
|
|
@ -133,8 +195,6 @@ mod imp {
|
|||
|
||||
#[property(get, set)]
|
||||
pub(super) orientation: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
pub(super) unit_factor: Cell<f64>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
|
@ -169,7 +229,9 @@ mod imp {
|
|||
|
||||
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_modal(true);
|
||||
|
|
@ -177,6 +239,7 @@ mod imp {
|
|||
self.alignment.connect_selected_notify(
|
||||
glib::clone!(@weak obj => move |_| obj.on_margin_vertical_changed()),
|
||||
);
|
||||
|
||||
self.alignment
|
||||
.set_expression(Some(gtk::ClosureExpression::new::<glib::GString>(
|
||||
[] as [gtk::Expression; 0],
|
||||
|
|
@ -185,13 +248,13 @@ mod imp {
|
|||
),
|
||||
)));
|
||||
|
||||
gtk::ClosureExpression::new::<glib::GString>(
|
||||
[] as [gtk::Expression; 0],
|
||||
glib::closure!(
|
||||
|s: gtk::StringObject| PageAlignment::from(s.string().as_str()).to_string()
|
||||
),
|
||||
self.margin_unit.connect_selected_notify(
|
||||
glib::clone!(@weak obj => move |_| obj.on_margin_unit_changed()),
|
||||
);
|
||||
|
||||
self.size_unit.connect_selected_notify(
|
||||
glib::clone!(@weak obj => move |_| obj.on_size_unit_changed()),
|
||||
);
|
||||
self.width
|
||||
.connect_value_notify(glib::clone!(@weak obj => move |_| obj.on_width_changed()));
|
||||
self.margin_horizontal.connect_value_notify(
|
||||
|
|
@ -228,7 +291,7 @@ mod imp {
|
|||
.unwrap_or_default();
|
||||
imp.title.set_title(&gettext_f(
|
||||
// Translators: {} is a placeholder for the filename
|
||||
"Print {}",
|
||||
"Print “{}”",
|
||||
&[&basename],
|
||||
));
|
||||
if let Some(printer) = operation.print_settings().and_then(|x| x.printer()) {
|
||||
|
|
@ -245,10 +308,9 @@ mod imp {
|
|||
obj.set_ranges();
|
||||
|
||||
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();
|
||||
|
||||
|
|
@ -309,13 +371,26 @@ impl LpPrint {
|
|||
obj
|
||||
}
|
||||
|
||||
pub fn unit(&self) -> glib::GString {
|
||||
self.imp()
|
||||
.unit
|
||||
.selected_item()
|
||||
.and_downcast::<gtk::StringObject>()
|
||||
.map(|x| x.string())
|
||||
.unwrap_or_default()
|
||||
fn size_unit(&self) -> Unit {
|
||||
Unit::from(
|
||||
self.imp()
|
||||
.size_unit
|
||||
.selected_item()
|
||||
.and_downcast::<gtk::StringObject>()
|
||||
.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 {
|
||||
|
|
@ -344,7 +419,7 @@ impl LpPrint {
|
|||
|
||||
/// Returns user selected image width in pixels
|
||||
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 {
|
||||
|
|
@ -366,7 +441,7 @@ impl LpPrint {
|
|||
|
||||
/// Returns user selected left margin in pixels
|
||||
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 {
|
||||
|
|
@ -393,7 +468,7 @@ impl LpPrint {
|
|||
|
||||
/// Returns user selected top margin in pixels
|
||||
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 {
|
||||
|
|
@ -415,25 +490,31 @@ impl LpPrint {
|
|||
fn set_ranges(&self) {
|
||||
let imp = self.imp();
|
||||
|
||||
let max_height =
|
||||
self.page_setup().page_height(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
||||
|
||||
let max_width =
|
||||
self.page_setup().page_width(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
||||
imp.width.set_range(self.unit_factor(), max_width);
|
||||
let size_unit = self.size_unit();
|
||||
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();
|
||||
imp.width.set_range(
|
||||
size_unit.ceil(self.width_unit_factor()),
|
||||
size_unit.floor(max_width * self.width_unit_factor()),
|
||||
);
|
||||
|
||||
let margin_unit = self.margin_unit();
|
||||
let min_horizontal_margin = f64::max(
|
||||
self.page_setup().left_margin(gtk::Unit::Inch),
|
||||
self.page_setup().right_margin(gtk::Unit::Inch),
|
||||
) * self.dpi()
|
||||
* self.unit_factor();
|
||||
imp.margin_horizontal
|
||||
.set_range(min_horizontal_margin, min_horizontal_margin + max_width);
|
||||
* self.margin_unit_factor();
|
||||
imp.margin_horizontal.set_range(
|
||||
margin_unit.ceil(min_horizontal_margin),
|
||||
margin_unit.floor(min_horizontal_margin + max_width * self.margin_unit_factor()),
|
||||
);
|
||||
|
||||
let min_vertical_margin =
|
||||
self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
|
||||
imp.margin_vertical
|
||||
.set_range(min_vertical_margin, min_vertical_margin + max_height);
|
||||
self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi() * self.margin_unit_factor();
|
||||
imp.margin_vertical.set_range(
|
||||
margin_unit.ceil(min_vertical_margin),
|
||||
margin_unit.floor(min_vertical_margin + max_height * self.margin_unit_factor()),
|
||||
);
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
|
|
@ -448,35 +529,42 @@ impl LpPrint {
|
|||
self.draw_preview();
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
pub fn unit_selected(&self) {
|
||||
fn on_size_unit_changed(&self) {
|
||||
let imp = self.imp();
|
||||
|
||||
let (unit_factor, digits) = match self.unit().as_str() {
|
||||
"cm" => (2.54 / self.dpi(), 2),
|
||||
"in" => (1. / self.dpi(), 2),
|
||||
"px" => (1., 0),
|
||||
unit => {
|
||||
log::error!("Unknown unit '{unit}'");
|
||||
(1., 2)
|
||||
}
|
||||
};
|
||||
let (orig_width, orig_height) = self.image().image_size();
|
||||
|
||||
let update_factor = unit_factor / self.unit_factor();
|
||||
let width = imp.width.value() * update_factor;
|
||||
let unit = self.size_unit();
|
||||
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_vertical = imp.margin_vertical.value() * update_factor;
|
||||
|
||||
self.set_unit_factor(unit_factor);
|
||||
self.set_margin_unit_factor(unit_factor);
|
||||
self.set_ranges();
|
||||
|
||||
imp.width.set_digits(digits);
|
||||
imp.width.set_value(width);
|
||||
|
||||
imp.margin_horizontal.set_digits(digits);
|
||||
imp.margin_horizontal.set_digits(unit.digits());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue