print: Show filename and printer in title

Part-of: <https://gitlab.gnome.org/GNOME/loupe/-/merge_requests/240>
This commit is contained in:
Sophie Herold 2023-06-21 17:36:56 +02:00 • committed by Christopher Davis
parent 9bfa9f7294
commit 65af818567
3 changed files with 226 additions and 112 deletions

View file

@ -21,6 +21,9 @@
<object class="AdwHeaderBar">
<property name="show-start-title-buttons">false</property>
<property name="show-end-title-buttons">false</property>
<property name="title-widget">
<object class="AdwWindowTitle" id="title" />
</property>
<child type="start">
<object class="GtkButton">
<property name="label" translatable="yes">Back</property>
@ -78,30 +81,19 @@
</object>
</child>
<child>
<object class="AdwActionRow">
<object class="AdwComboRow" id="alignment">
<property name="title" translatable="yes">Alignment</property>
<child>
<object class="GtkBox">
<property name="valign">center</property>
<style>
<class name="linked" />
</style>
<child>
<object class="GtkButton">
<property name="icon-name">center-on-page-horizontal-symbolic</property>
<property name="action-name">print.center-horizontally</property>
<property name="tooltip-text" translatable="yes">Center image horizontally</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">center-on-page-vertical-symbolic</property>
<property name="action-name">print.center-vertically</property>
<property name="tooltip-text" translatable="yes">Center image vertically</property>
</object>
</child>
<property name="model">
<object class="GtkStringList">
<items>
<item>center</item>
<item>top</item>
<item>bottom</item>
<item>left</item>
<item>right</item>
</items>
</object>
</child>
</property>
</object>
</child>
</object>
@ -110,15 +102,13 @@
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Margins</property>
<child>
<object class="AdwSpinRow" id="margin_left">
<object class="AdwSpinRow" id="margin_horizontal">
<property name="title" translatable="yes">Horizontal</property>
<property name="digits">2</property>
</object>
</child>
<child>
<object class="AdwSpinRow" id="margin_top">
<object class="AdwSpinRow" id="margin_vertical">
<property name="title" translatable="yes">Vertical</property>
<property name="digits">2</property>
</object>
</child>
</object>
@ -129,7 +119,6 @@
<child>
<object class="AdwSpinRow" id="width">
<property name="title" translatable="yes">Width</property>
<property name="digits">2</property>
</object>
</child>
<child>

View file

@ -19,6 +19,7 @@
use crate::decoder;
use crate::deps::*;
use crate::util::gettext::*;
use crate::widgets::{LpImage, LpPrintPreview};
use adw::prelude::*;
@ -29,6 +30,70 @@ use once_cell::sync::OnceCell;
use std::cell::{Cell, RefCell};
#[derive(Default, Clone, Copy)]
struct PageAlignment {
horizontal: HAlignment,
vertical: VAlignment,
}
#[derive(Default, Clone, Copy)]
enum HAlignment {
Left,
#[default]
Center,
Right,
}
#[derive(Default, Clone, Copy)]
enum VAlignment {
Top,
#[default]
Middle,
Bottom,
}
impl From<&str> for PageAlignment {
fn from(s: &str) -> Self {
let alignment = match s {
"top" => (HAlignment::Center, VAlignment::Top),
"center" => (HAlignment::Center, VAlignment::Middle),
"bottom" => (HAlignment::Center, VAlignment::Bottom),
"left" => (HAlignment::Left, VAlignment::Middle),
"right" => (HAlignment::Right, VAlignment::Middle),
pos => {
log::error!("Unkown alignment '{pos}'");
(HAlignment::default(), VAlignment::default())
}
};
Self::from(alignment)
}
}
impl From<(HAlignment, VAlignment)> for PageAlignment {
fn from((horizontal, vertical): (HAlignment, VAlignment)) -> Self {
Self {
horizontal,
vertical,
}
}
}
impl std::fmt::Display for PageAlignment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let s = match (self.horizontal, self.vertical) {
(HAlignment::Center, VAlignment::Top) => gettext("Top"),
(HAlignment::Center, VAlignment::Middle) => gettext("Center"),
(HAlignment::Center, VAlignment::Bottom) => gettext("Bottom"),
(HAlignment::Left, VAlignment::Middle) => gettext("Left"),
(HAlignment::Right, VAlignment::Middle) => gettext("Right"),
_ => String::from("Unsupported (Error)"),
};
f.write_str(&s)
}
}
mod imp {
use super::*;
@ -36,19 +101,25 @@ mod imp {
#[template(file = "../../data/gtk/print.ui")]
#[properties(wrapper_type = super::LpPrint)]
pub struct LpPrint {
#[template_child]
pub(super) title: TemplateChild<adw::WindowTitle>,
#[template_child]
pub(super) preview: TemplateChild<LpPrintPreview>,
// ListBox entries
#[template_child]
pub(super) alignment: TemplateChild<adw::ComboRow>,
#[template_child]
pub(super) margin_horizontal: TemplateChild<adw::SpinRow>,
#[template_child]
pub(super) margin_vertical: TemplateChild<adw::SpinRow>,
#[template_child]
pub(super) width: TemplateChild<adw::SpinRow>,
#[template_child]
pub(super) scale: TemplateChild<gtk::Label>,
#[template_child]
pub(super) margin_left: TemplateChild<adw::SpinRow>,
#[template_child]
pub(super) margin_top: TemplateChild<adw::SpinRow>,
#[template_child]
pub(super) unit: TemplateChild<adw::ComboRow>,
#[property(get, set, builder().construct_only())]
@ -84,14 +155,6 @@ mod imp {
print.back().await;
});
klass.install_action("print.center-horizontally", None, |print, _, _| {
print.center_horizontally();
});
klass.install_action("print.center-vertically", None, |print, _, _| {
print.center_vertically();
});
klass.install_property_action("print.orientation", "orientation");
}
@ -111,13 +174,31 @@ mod imp {
obj.set_transient_for(Some(&obj.parent_window()));
obj.set_modal(true);
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],
glib::closure!(
|s: gtk::StringObject| PageAlignment::from(s.string().as_str()).to_string()
),
)));
gtk::ClosureExpression::new::<glib::GString>(
[] as [gtk::Expression; 0],
glib::closure!(
|s: gtk::StringObject| PageAlignment::from(s.string().as_str()).to_string()
),
);
self.width
.connect_value_notify(glib::clone!(@weak obj => move |_| obj.on_width_changed()));
self.margin_left.connect_value_notify(
glib::clone!(@weak obj => move |_| obj.on_margin_left_changed()),
self.margin_horizontal.connect_value_notify(
glib::clone!(@weak obj => move |_| obj.on_margin_horizontal_changed()),
);
self.margin_top.connect_value_notify(
glib::clone!(@weak obj => move |_| obj.on_margin_top_changed()),
self.margin_vertical.connect_value_notify(
glib::clone!(@weak obj => move |_| obj.on_margin_vertical_changed()),
);
self.print_operation
@ -135,36 +216,52 @@ mod imp {
op.set_n_pages(1);
});
self.print_operation.connect_draw_page(
glib::clone!(@weak obj => move |_operation, _context, _page_nr| {
let imp = obj.imp();
self.print_operation.connect_draw_page(glib::clone!(@weak obj =>
move |operation, _context, _page_nr| {
let imp = obj.imp();
imp.width.adjustment().set_step_increment(1.);
imp.width.adjustment().set_page_increment(5.);
imp.margin_left.adjustment().set_step_increment(1.);
imp.margin_left.adjustment().set_page_increment(5.);
imp.margin_top.adjustment().set_step_increment(1.);
imp.margin_top.adjustment().set_page_increment(5.);
let basename = obj
.image()
.file()
.and_then(|f| f.basename())
.map(|x| x.display().to_string())
.unwrap_or_default();
imp.title.set_title(&gettext_f(
// Translators: {} is a placeholder for the filename
"Print {}",
&[&basename],
));
if let Some(printer) = operation.print_settings().and_then(|x| x.printer()) {
imp.title.set_subtitle(&printer);
}
obj.set_ranges();
imp.width.adjustment().set_step_increment(1.);
imp.width.adjustment().set_page_increment(5.);
imp.margin_horizontal.adjustment().set_step_increment(1.);
imp.margin_horizontal.adjustment().set_page_increment(5.);
imp.margin_vertical.adjustment().set_step_increment(1.);
imp.margin_vertical.adjustment().set_page_increment(5.);
imp.width.set_value(obj.image().image_size().0 as f64);
obj.center_horizontally();
obj.set_ranges();
obj.unit_selected();
imp.width.set_value(obj.image().image_size().0 as f64);
// TODO: Select center
//obj.center_horizontally();
imp.print_operation.cancel();
obj.unit_selected();
let orientation = match obj.page_setup().orientation() {
gtk::PageOrientation::Portrait => "portrait",
gtk::PageOrientation::Landscape => "landscape",
_ => "other",
};
obj.set_orientation(orientation);
imp.print_operation.cancel();
obj.set_visible(true);
}),
);
let orientation = match obj.page_setup().orientation() {
gtk::PageOrientation::Portrait => "portrait",
gtk::PageOrientation::Landscape => "landscape",
_ => "other",
};
obj.set_orientation(orientation);
obj.set_visible(true);
}
));
}
fn properties() -> &'static [glib::ParamSpec] {
@ -233,11 +330,29 @@ impl LpPrint {
self.draw_preview();
}
fn user_alignment(&self) -> PageAlignment {
let s = self
.imp()
.alignment
.selected_item()
.and_then(|x| x.downcast::<gtk::StringObject>().ok())
.map(|x| x.string())
.unwrap_or_default();
PageAlignment::from(s.as_str())
}
/// Returns user selected image width in pixels
pub fn user_width(&self) -> f64 {
f64::max(1., self.imp().width.value() / self.unit_factor())
}
pub fn user_height(&self) -> f64 {
let (_, orig_height) = self.image().image_size();
f64::max(1., orig_height as f64 * self.user_scale())
}
/// Returns scaling of the original image based on selected image size
pub fn user_scale(&self) -> f64 {
let (orig_width, _) = self.image().image_size();
@ -245,22 +360,50 @@ impl LpPrint {
self.user_width() / orig_width as f64
}
pub fn on_margin_left_changed(&self) {
pub fn on_margin_horizontal_changed(&self) {
self.draw_preview();
}
/// Returns user selected left margin in pixels
pub fn user_margin_left(&self) -> f64 {
self.imp().margin_left.value() / self.unit_factor()
pub fn user_margin_horizontal(&self) -> f64 {
self.imp().margin_horizontal.value() / self.unit_factor()
}
pub fn on_margin_top_changed(&self) {
pub fn effective_margin_left(&self) -> f64 {
match self.user_alignment().horizontal {
HAlignment::Left => self.user_margin_horizontal(),
HAlignment::Center => (self.paper_width() - self.user_width()) / 2.,
HAlignment::Right => {
self.paper_width() - self.user_width() - self.user_margin_horizontal()
}
}
}
pub fn paper_width(&self) -> f64 {
self.page_setup().paper_width(gtk::Unit::Inch) * self.dpi()
}
pub fn paper_height(&self) -> f64 {
self.page_setup().paper_height(gtk::Unit::Inch) * self.dpi()
}
pub fn on_margin_vertical_changed(&self) {
self.draw_preview();
}
/// Returns user selected top margin in pixels
pub fn user_margin_top(&self) -> f64 {
self.imp().margin_top.value() / self.unit_factor()
pub fn user_margin_vertical(&self) -> f64 {
self.imp().margin_vertical.value() / self.unit_factor()
}
pub fn effective_margin_top(&self) -> f64 {
match self.user_alignment().vertical {
VAlignment::Top => self.user_margin_vertical(),
VAlignment::Middle => (self.paper_height() - self.user_height()) / 2.,
VAlignment::Bottom => {
self.paper_height() - self.user_height() - self.user_margin_vertical()
}
}
}
/// Redraws the preview widget child
@ -268,27 +411,6 @@ impl LpPrint {
self.imp().preview.queue_resize();
}
/// Centers the image horizontally
fn center_horizontally(&self) {
let margin_left =
(self.page_setup().paper_width(gtk::Unit::Inch) * self.dpi() - self.user_width()) / 2.;
self.imp()
.margin_left
.set_value(margin_left * self.unit_factor());
}
/// Centers the image vertically
fn center_vertically(&self) {
let user_height = self.image().image_size().1 as f64 * self.user_scale();
let margin_top =
(self.page_setup().paper_height(gtk::Unit::Inch) * self.dpi() - user_height) / 2.;
self.imp()
.margin_top
.set_value(margin_top * self.unit_factor());
}
/// Sets the allowed ranges for the spin button based on current unit
fn set_ranges(&self) {
let imp = self.imp();
@ -300,15 +422,18 @@ impl LpPrint {
self.page_setup().page_width(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
imp.width.set_range(self.unit_factor(), max_width);
let min_left_margin =
self.page_setup().left_margin(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
imp.margin_left
.set_range(min_left_margin, min_left_margin + max_width);
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);
let min_top_margin =
let min_vertical_margin =
self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi() * self.unit_factor();
imp.margin_top
.set_range(min_top_margin, min_top_margin + max_height);
imp.margin_vertical
.set_range(min_vertical_margin, min_vertical_margin + max_height);
}
#[template_callback]
@ -339,8 +464,8 @@ impl LpPrint {
let update_factor = unit_factor / self.unit_factor();
let width = imp.width.value() * update_factor;
let margin_left = imp.margin_left.value() * update_factor;
let margin_top = imp.margin_top.value() * update_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_ranges();
@ -348,11 +473,11 @@ impl LpPrint {
imp.width.set_digits(digits);
imp.width.set_value(width);
imp.margin_left.set_digits(digits);
imp.margin_left.set_value(margin_left);
imp.margin_horizontal.set_digits(digits);
imp.margin_horizontal.set_value(margin_horizontal);
imp.margin_top.set_digits(digits);
imp.margin_top.set_value(margin_top);
imp.margin_vertical.set_digits(digits);
imp.margin_vertical.set_value(margin_vertical);
}
pub fn run(&self) {
@ -461,10 +586,10 @@ impl LpPrint {
let cairo_context = print_context.cairo_context();
cairo_context.scale(cairo_scale, cairo_scale);
let margin_left =
self.user_margin_left() - self.page_setup().left_margin(gtk::Unit::Inch) * self.dpi();
let margin_top =
self.user_margin_top() - self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi();
let margin_left = self.effective_margin_left()
- self.page_setup().left_margin(gtk::Unit::Inch) * self.dpi();
let margin_top = self.effective_margin_top()
- self.page_setup().top_margin(gtk::Unit::Inch) * self.dpi();
cairo_context
.set_source_surface(cairo_surface, margin_left, margin_top)

View file

@ -79,8 +79,8 @@ mod imp {
snapshot.save();
let scale = obj.print().user_scale() * self.display_scale();
let margin_left = obj.print().user_margin_left() * self.display_scale();
let margin_top = obj.print().user_margin_top() * self.display_scale();
let margin_left = obj.print().effective_margin_left() * self.display_scale();
let margin_top = obj.print().effective_margin_top() * self.display_scale();
if let Some(texture) = self.obj().print().image().print_data(scale) {
let area = graphene::Rect::new(