ui: Non-circular overlays and less buttons
Part-of: <https://gitlab.gnome.org/GNOME/loupe/-/merge_requests/450>
This commit is contained in:
parent
e5930b134c
commit
0b4c69459f
18 changed files with 470 additions and 93 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
|
@ -1287,9 +1287,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgweather"
|
name = "libgweather"
|
||||||
|
|
@ -1388,6 +1388,7 @@ dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"kamadak-exif",
|
"kamadak-exif",
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
|
"libc",
|
||||||
"libgweather",
|
"libgweather",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ gufo-common = { version = "0.1.0", features = ["serde"] }
|
||||||
gvdb-macros = "0.1.6"
|
gvdb-macros = "0.1.6"
|
||||||
indexmap = "2.0.0"
|
indexmap = "2.0.0"
|
||||||
kamadak-exif = "0.5.5"
|
kamadak-exif = "0.5.5"
|
||||||
|
libc = "0.2.158"
|
||||||
libgweather = "4.4.0"
|
libgweather = "4.4.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 13.398438 2.011719 c -0.394532 0.027343 -0.765626 0.210937 -1.027344 0.507812 l -5.78125 6.609375 l -1.890625 -2.519531 c -0.496094 -0.664063 -1.4375 -0.796875 -2.101563 -0.300781 c -0.316406 0.238281 -0.527344 0.59375 -0.582031 0.988281 c -0.058594 0.394531 0.046875 0.796875 0.285156 1.113281 l 3 4 c 0.273438 0.359375 0.691407 0.582032 1.144531 0.597656 c 0.449219 0.015626 0.886719 -0.171874 1.183594 -0.511718 l 7 -8 c 0.542969 -0.625 0.480469 -1.570313 -0.140625 -2.117188 c -0.300781 -0.261718 -0.691406 -0.394531 -1.089843 -0.367187 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 710 B |
2
data/resources/icons/scalable/actions/minus-symbolic.svg
Normal file
2
data/resources/icons/scalable/actions/minus-symbolic.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 3 7 h 10 v 2 h -10 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 188 B |
2
data/resources/icons/scalable/actions/plus-symbolic.svg
Normal file
2
data/resources/icons/scalable/actions/plus-symbolic.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 7 3 v 4 h -4 v 2 h 4 v 4 h 2 v -4 h 4 v -2 h -4 v -4 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 222 B |
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m10.875 10.062c-0.8125 0.14844-1.1055 1.1602-0.5 1.7188l3 3c0.95703 0.9375 2.3633-0.5 1.4062-1.4375l-3-3c-0.23438-0.23828-0.57422-0.34766-0.90625-0.28125z" fill="#222"/>
|
||||||
|
<path d="m6.5703 0.0625c-3.5781 0-6.5 2.9219-6.5 6.5s2.9219 6.5 6.5 6.5c3.5781 0 6.5-2.9219 6.5-6.5s-2.9219-6.5-6.5-6.5zm0 2c2.5 0 4.5 2.0039 4.5 4.5 0 2.5-2 4.5-4.5 4.5-2.4961 0-4.5-2-4.5-4.5 0-2.4961 2.0039-4.5 4.5-4.5z" fill="#222"/>
|
||||||
|
<g transform="translate(-14.443 -19.459)" fill="#222">
|
||||||
|
<path d="m21.023 23c0.53906 0 0.97656 0.4375 0.97656 0.97656v4.0898c0 0.53906-0.4375 0.97656-0.97656 0.97656-0.53906 0-0.97656-0.4375-0.97656-0.97656v-4.0898c0-0.53906 0.4375-0.97656 0.97656-0.97656z"/>
|
||||||
|
<path d="m19.027 25h3.9727c0.55078 0 1 0.44922 1 1s-0.44922 1-1 1h-3.9727c-0.55078 0-1-0.44922-1-1s0.44922-1 1-1z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 952 B |
|
|
@ -1,7 +1,13 @@
|
||||||
/* Overlay controls for next, zoom, fullscreen */
|
/* Overlay controls for prev/next and zoom */
|
||||||
button.osd.circular {
|
.osd-box {
|
||||||
min-width: 42px;
|
border-radius: 12px;
|
||||||
min-height: 42px;
|
background: rgba(0, 0, 0, 0.65);
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.osd-box menubutton button {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreen revealer:not(.raised) .fullscreen-osd {
|
.fullscreen revealer:not(.raised) .fullscreen-osd {
|
||||||
|
|
@ -65,4 +71,4 @@ dialog.error-details textview {
|
||||||
.error-message {
|
.error-message {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
}
|
}
|
||||||
1
news.d/48.alpha/changed-zoom-overlay-buttons
Normal file
1
news.d/48.alpha/changed-zoom-overlay-buttons
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
The design of the overlay buttons, especially for zoom controls has been reworked. A new menu supports selecting from pre-defined zoom levels as well as entering a specific zoom level.
|
||||||
32
src/util.rs
32
src/util.rs
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
pub mod gettext;
|
pub mod gettext;
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
|
@ -229,3 +230,34 @@ pub fn contrast_ratio(color1: &gdk::RGBA, color2: &gdk::RGBA) -> f32 {
|
||||||
|
|
||||||
(l1 + 0.05) / (l2 + 0.05)
|
(l1 + 0.05) / (l2 + 0.05)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LocaleSettings {
|
||||||
|
pub decimal_point: Option<String>,
|
||||||
|
pub thousands_sep: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn locale_settings() -> LocaleSettings {
|
||||||
|
unsafe {
|
||||||
|
let lconv = libc::localeconv();
|
||||||
|
let mut locale_settings = LocaleSettings::default();
|
||||||
|
|
||||||
|
if lconv.is_null() {
|
||||||
|
return locale_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lconv = *lconv;
|
||||||
|
|
||||||
|
if !(lconv).decimal_point.is_null() {
|
||||||
|
let s = CStr::from_ptr(lconv.decimal_point);
|
||||||
|
locale_settings.decimal_point = s.to_str().map(|x| x.to_string()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lconv.thousands_sep.is_null() {
|
||||||
|
let s = CStr::from_ptr(lconv.thousands_sep);
|
||||||
|
locale_settings.thousands_sep = s.to_str().map(|x| x.to_string()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
locale_settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,7 @@ mod imp {
|
||||||
pub(super) zoom_animation: OnceCell<adw::TimedAnimation>,
|
pub(super) zoom_animation: OnceCell<adw::TimedAnimation>,
|
||||||
/// Targeted zoom level, might differ from `zoom` when animation is
|
/// Targeted zoom level, might differ from `zoom` when animation is
|
||||||
/// running
|
/// running
|
||||||
|
#[property(get, set = Self::set_zoom_target)]
|
||||||
pub(super) zoom_target: Cell<f64>,
|
pub(super) zoom_target: Cell<f64>,
|
||||||
/// Point in image that should stay under the cursor during animation.
|
/// Point in image that should stay under the cursor during animation.
|
||||||
/// The value is in image coordinates.
|
/// The value is in image coordinates.
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ impl imp::LpImage {
|
||||||
log::trace!("Setting zoom target {zoom_target}");
|
log::trace!("Setting zoom target {zoom_target}");
|
||||||
|
|
||||||
self.zoom_target.set(zoom_target);
|
self.zoom_target.set(zoom_target);
|
||||||
|
self.obj().notify_zoom_target();
|
||||||
|
|
||||||
if self.obj().zoom() == self.zoom_target.get() {
|
if self.obj().zoom() == self.zoom_target.get() {
|
||||||
self.request_tiles();
|
self.request_tiles();
|
||||||
|
|
@ -365,11 +366,16 @@ impl LpImage {
|
||||||
|
|
||||||
/// Zoom to specific level with animation not snapping to best-fit
|
/// Zoom to specific level with animation not snapping to best-fit
|
||||||
///
|
///
|
||||||
/// Used for zooming to 100% or 200%
|
/// Used for zooming to 100% or 200% etc
|
||||||
pub fn zoom_to_exact(&self, zoom: f64) {
|
pub fn zoom_to_exact(&self, zoom: f64) {
|
||||||
self.imp().zoom_to_full(zoom, true, false, false);
|
self.imp().zoom_to_full(zoom, true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as `zoom_to_exact` but zoom to center
|
||||||
|
pub fn zoom_to_exact_center(&self, zoom: f64) {
|
||||||
|
self.imp().zoom_to_full(zoom, true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_best_fit(&self) -> bool {
|
pub fn is_best_fit(&self) -> bool {
|
||||||
self.imp().best_fit.get()
|
self.imp().best_fit.get()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,10 @@
|
||||||
<attribute name="label" translatable="yes">_Open With…</attribute>
|
<attribute name="label" translatable="yes">_Open With…</attribute>
|
||||||
<attribute name="action">win.open-with</attribute>
|
<attribute name="action">win.open-with</attribute>
|
||||||
</item>
|
</item>
|
||||||
<!--<item>
|
|
||||||
<attribute name="label" translatable="yes">_Display On…</attribute>
|
|
||||||
<attribute name="action">win.display-on</attribute>
|
|
||||||
</item>-->
|
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">_Print…</attribute>
|
<attribute name="label" translatable="yes">_Print…</attribute>
|
||||||
<attribute name="action">win.print</attribute>
|
<attribute name="action">win.print</attribute>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<attribute name="label" translatable="yes">_Copy</attribute>
|
|
||||||
<attribute name="action">win.copy-image</attribute>
|
|
||||||
</item>
|
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<attribute name="label" translatable="yes">Rotate</attribute>
|
<attribute name="label" translatable="yes">Rotate</attribute>
|
||||||
|
|
@ -34,6 +26,14 @@
|
||||||
<attribute name="label" translatable="yes">_Set as Background…</attribute>
|
<attribute name="label" translatable="yes">_Set as Background…</attribute>
|
||||||
<attribute name="action">win.set-background</attribute>
|
<attribute name="action">win.set-background</attribute>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">_Delete</attribute>
|
||||||
|
<attribute name="action">win.trash</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">_Copy</attribute>
|
||||||
|
<attribute name="action">win.copy-image</attribute>
|
||||||
|
</item>
|
||||||
</section>
|
</section>
|
||||||
</menu>
|
</menu>
|
||||||
<template class="LpImagePage" parent="AdwBin">
|
<template class="LpImagePage" parent="AdwBin">
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ use crate::decoder::DecoderError;
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::file_model::LpFileModel;
|
use crate::file_model::LpFileModel;
|
||||||
use crate::util::gettext::*;
|
use crate::util::gettext::*;
|
||||||
use crate::util::{Direction, Position};
|
use crate::util::{self, Direction, Position};
|
||||||
use crate::widgets::{LpImage, LpImagePage, LpPrint, LpSlidingView};
|
use crate::widgets::{LpImage, LpImagePage, LpPrint, LpSlidingView};
|
||||||
|
|
||||||
// The number of pages we want to buffer
|
// The number of pages we want to buffer
|
||||||
|
|
@ -63,18 +63,38 @@ mod imp {
|
||||||
/// Direct child of this Adw::Bin
|
/// Direct child of this Adw::Bin
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) bin_child: TemplateChild<gtk::Widget>,
|
pub(super) bin_child: TemplateChild<gtk::Widget>,
|
||||||
|
|
||||||
/// overlayed controls
|
/// overlayed controls
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) controls_box_start: TemplateChild<gtk::Widget>,
|
pub(super) controls_box_start: TemplateChild<gtk::Widget>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
pub(super) zoom_toggle: TemplateChild<gtk::ToggleButton>,
|
||||||
|
#[template_child]
|
||||||
pub(super) controls_box_start_events: TemplateChild<gtk::EventControllerMotion>,
|
pub(super) controls_box_start_events: TemplateChild<gtk::EventControllerMotion>,
|
||||||
|
|
||||||
/// overlayed controls
|
/// overlayed controls
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) controls_box_end: TemplateChild<gtk::Widget>,
|
pub(super) controls_box_end: TemplateChild<gtk::Widget>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) controls_box_end_events: TemplateChild<gtk::EventControllerMotion>,
|
pub(super) controls_box_end_events: TemplateChild<gtk::EventControllerMotion>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) fullscreen_button: TemplateChild<gtk::Button>,
|
pub(super) zoom_menu_button: TemplateChild<gtk::MenuButton>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_list: TemplateChild<gtk::ListBox>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_300: TemplateChild<gtk::ListBoxRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_200: TemplateChild<gtk::ListBoxRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_100: TemplateChild<gtk::ListBoxRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_66: TemplateChild<gtk::ListBoxRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_to_50: TemplateChild<gtk::ListBoxRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) zoom_value: TemplateChild<gtk::Entry>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) submit_zoom: TemplateChild<gtk::Button>,
|
||||||
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub sliding_view: TemplateChild<LpSlidingView>,
|
pub sliding_view: TemplateChild<LpSlidingView>,
|
||||||
|
|
@ -98,6 +118,9 @@ mod imp {
|
||||||
|
|
||||||
#[property(get = Self::is_next_available)]
|
#[property(get = Self::is_next_available)]
|
||||||
_is_next_available: PhantomData<bool>,
|
_is_next_available: PhantomData<bool>,
|
||||||
|
|
||||||
|
#[property(get, set)]
|
||||||
|
zoom_toggle_state: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -148,10 +171,10 @@ mod imp {
|
||||||
move || obj.target_page_reached()
|
move || obj.target_page_reached()
|
||||||
));
|
));
|
||||||
|
|
||||||
let signal_group = obj.current_image_signals();
|
let current_image_signal_group = obj.current_image_signals();
|
||||||
|
|
||||||
let view = &*obj;
|
let view = &*obj;
|
||||||
signal_group.connect_closure(
|
current_image_signal_group.connect_closure(
|
||||||
"notify::file",
|
"notify::file",
|
||||||
true,
|
true,
|
||||||
glib::closure_local!(
|
glib::closure_local!(
|
||||||
|
|
@ -163,7 +186,7 @@ mod imp {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
signal_group.connect_closure(
|
current_image_signal_group.connect_closure(
|
||||||
"notify::is-deleted",
|
"notify::is-deleted",
|
||||||
true,
|
true,
|
||||||
glib::closure_local!(
|
glib::closure_local!(
|
||||||
|
|
@ -175,6 +198,97 @@ mod imp {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
current_image_signal_group.connect_closure(
|
||||||
|
"notify::zoom-target",
|
||||||
|
true,
|
||||||
|
glib::closure_local!(
|
||||||
|
#[watch]
|
||||||
|
view,
|
||||||
|
move |img: LpImage, _: glib::ParamSpec| {
|
||||||
|
let mut percent =
|
||||||
|
((img.zoom_target() * 10_000.).round() / 100.).to_string();
|
||||||
|
|
||||||
|
if let Some(decimal) = util::locale_settings().decimal_point {
|
||||||
|
percent = percent.replace('.', &decimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
view.imp()
|
||||||
|
.zoom_value
|
||||||
|
.set_text(&gettext_f("{} %", [percent]));
|
||||||
|
view.imp().zoom_value.select_region(0, -1);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.zoom_toggle.connect_clicked(clone!(
|
||||||
|
#[weak]
|
||||||
|
obj,
|
||||||
|
move |button| {
|
||||||
|
if let Some(page) = obj.current_page() {
|
||||||
|
if button.is_active() {
|
||||||
|
page.image().zoom_in_center()
|
||||||
|
} else {
|
||||||
|
page.image().zoom_best_fit()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.zoom_to_list.connect_row_activated(clone!(
|
||||||
|
#[weak]
|
||||||
|
obj,
|
||||||
|
move |_, row| {
|
||||||
|
let imp = obj.imp();
|
||||||
|
let value = if row == &*imp.zoom_to_300 {
|
||||||
|
3.
|
||||||
|
} else if row == &*imp.zoom_to_200 {
|
||||||
|
2.
|
||||||
|
} else if row == &*imp.zoom_to_100 {
|
||||||
|
1.
|
||||||
|
} else if row == &*imp.zoom_to_66 {
|
||||||
|
0.66
|
||||||
|
} else if row == &*imp.zoom_to_50 {
|
||||||
|
0.5
|
||||||
|
} else {
|
||||||
|
log::error!("Activated unknown entry in zoom to popover.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(image) = obj.current_image() {
|
||||||
|
image.zoom_to_exact_center(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close popover after click
|
||||||
|
imp.zoom_menu_button.set_active(false);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.submit_zoom.connect_clicked(clone!(
|
||||||
|
#[weak]
|
||||||
|
obj,
|
||||||
|
move |_| {
|
||||||
|
if let Some(page) = obj.current_page() {
|
||||||
|
let mut value = obj.imp().zoom_value.text().to_string();
|
||||||
|
let locale_settings = util::locale_settings();
|
||||||
|
|
||||||
|
if let Some(thousands) = locale_settings.thousands_sep {
|
||||||
|
value = value.replace(&thousands, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(decimal) = locale_settings.decimal_point {
|
||||||
|
value = value.replace(&decimal, ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.replace('%', "");
|
||||||
|
value = value.trim().to_string();
|
||||||
|
|
||||||
|
if let Ok(value) = value.parse::<f64>() {
|
||||||
|
page.image().zoom_to_exact(value / 100.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
self.drag_source.set_exclusive(true);
|
self.drag_source.set_exclusive(true);
|
||||||
|
|
||||||
self.drag_source.connect_prepare(glib::clone!(
|
self.drag_source.connect_prepare(glib::clone!(
|
||||||
|
|
@ -678,16 +792,6 @@ impl LpImageView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_fullscreen_changed(&self, is_fullscreened: bool) {
|
|
||||||
let icon = if is_fullscreened {
|
|
||||||
"view-restore-symbolic"
|
|
||||||
} else {
|
|
||||||
"view-fullscreen-symbolic"
|
|
||||||
};
|
|
||||||
|
|
||||||
self.imp().fullscreen_button.set_icon_name(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotate_image(&self, angle: f64) {
|
pub fn rotate_image(&self, angle: f64) {
|
||||||
if let Some(current_page) = self.current_page() {
|
if let Some(current_page) = self.current_page() {
|
||||||
current_page.image().rotate_by(angle);
|
current_page.image().rotate_by(angle);
|
||||||
|
|
@ -770,4 +874,8 @@ impl LpImageView {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn zoom_menu_button(&self) -> gtk::MenuButton {
|
||||||
|
self.imp().zoom_menu_button.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@
|
||||||
<property name="margin-end">18</property>
|
<property name="margin-end">18</property>
|
||||||
<property name="margin-top">18</property>
|
<property name="margin-top">18</property>
|
||||||
<property name="margin-bottom">18</property>
|
<property name="margin-bottom">18</property>
|
||||||
<property name="spacing">12</property>
|
<property name="spacing">6</property>
|
||||||
|
<style>
|
||||||
|
<class name="osd-box" />
|
||||||
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="prev_button">
|
<object class="GtkButton" id="prev_button">
|
||||||
<property name="halign">start</property>
|
<property name="halign">start</property>
|
||||||
|
|
@ -26,8 +29,7 @@
|
||||||
<property name="action-name">win.previous</property>
|
<property name="action-name">win.previous</property>
|
||||||
<property name="tooltip-text" translatable="yes">Previous Image</property>
|
<property name="tooltip-text" translatable="yes">Previous Image</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="osd" />
|
<class name="flat" />
|
||||||
<class name="circular" />
|
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
@ -37,8 +39,7 @@
|
||||||
<property name="action-name">win.next</property>
|
<property name="action-name">win.next</property>
|
||||||
<property name="tooltip-text" translatable="yes">Next Image</property>
|
<property name="tooltip-text" translatable="yes">Next Image</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="osd" />
|
<class name="flat" />
|
||||||
<class name="circular" />
|
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
@ -55,38 +56,203 @@
|
||||||
<property name="margin-end">18</property>
|
<property name="margin-end">18</property>
|
||||||
<property name="margin-top">18</property>
|
<property name="margin-top">18</property>
|
||||||
<property name="margin-bottom">18</property>
|
<property name="margin-bottom">18</property>
|
||||||
<property name="spacing">12</property>
|
<style>
|
||||||
|
<class name="osd-box" />
|
||||||
|
</style>
|
||||||
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="zoom_out">
|
<object class="GtkRevealer">
|
||||||
<property name="icon-name">zoom-out-symbolic</property>
|
<property name="reveal-child" bind-source="LpImageView" bind-property="zoom-toggle-state" bind-flags="sync-create" />
|
||||||
<property name="action-name">win.zoom-out-center</property>
|
<property name="transition-type">slide-left</property>
|
||||||
<property name="tooltip-text" translatable="yes">Zoom Out</property>
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="zoom_out">
|
||||||
|
<property name="icon-name">minus-symbolic</property>
|
||||||
|
<property name="action-name">win.zoom-out-center</property>
|
||||||
|
<property name="tooltip-text" translatable="yes">Zoom Out</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="zoom_in">
|
||||||
|
<property name="margin-end">6</property>
|
||||||
|
<property name="icon-name">plus-symbolic</property>
|
||||||
|
<property name="action-name">win.zoom-in-center</property>
|
||||||
|
<property name="tooltip-text" translatable="yes">Zoom In</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="zoom_toggle">
|
||||||
|
<property name="margin-end">6</property>
|
||||||
|
<property name="icon-name">zoom-toggle-symbolic</property>
|
||||||
|
<property name="active" bind-source="LpImageView" bind-property="zoom-toggle-state" bind-flags="sync-create" />
|
||||||
|
<property name="tooltip-text" translatable="yes">Toggle Zoom</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="osd" />
|
<class name="flat" />
|
||||||
<class name="circular" />
|
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="zoom_in">
|
<object class="GtkMenuButton" id="zoom_menu_button">
|
||||||
<property name="icon-name">zoom-in-symbolic</property>
|
<property name="tooltip-text" translatable="yes">Zoom to Specific Level</property>
|
||||||
<property name="action-name">win.zoom-in-center</property>
|
<property name="direction">up</property>
|
||||||
<property name="tooltip-text" translatable="yes">Zoom In</property>
|
<property name="icon-name">pan-down-symbolic</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="osd" />
|
<class name="flat" />
|
||||||
<class name="circular" />
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="fullscreen_button">
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="action-name">win.toggle-fullscreen</property>
|
|
||||||
<property name="tooltip-text" translatable="yes">Toggle Fullscreen</property>
|
|
||||||
<style>
|
|
||||||
<class name="osd" />
|
|
||||||
<class name="circular" />
|
|
||||||
</style>
|
</style>
|
||||||
|
<property name="popover">
|
||||||
|
<!--
|
||||||
|
Use manual implementation instead of GtkPopoverMenu because:
|
||||||
|
1. We need to specify the shortcuts manually since called from the menu the zoom does not aim for the cursor.
|
||||||
|
2. Hovering other menu entries would steal the focus from the GtkEntry.
|
||||||
|
-->
|
||||||
|
<object class="GtkPopover">
|
||||||
|
<property name="default-widget">submit_zoom</property>
|
||||||
|
<style>
|
||||||
|
<class name="menu" />
|
||||||
|
</style>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="margin-top">6</property>
|
||||||
|
<property name="margin-end">6</property>
|
||||||
|
<property name="margin-bottom">6</property>
|
||||||
|
<property name="margin-start">6</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="zoom_to_list">
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="zoom_to_300">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label">300 %</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<property name="label">Ctrl+3</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="zoom_to_200">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label">200 %</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<property name="label">Ctrl+2</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="zoom_to_100">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label">100 %</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<property name="label">Ctrl+1</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="zoom_to_66">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label">66 %</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="zoom_to_50">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label">50 %</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="zoom_value">
|
||||||
|
<property name="activates-default">True</property>
|
||||||
|
<property name="input-purpose">number</property>
|
||||||
|
<property name="max-width-chars">8</property>
|
||||||
|
<property name="tooltip-text">Custom Zoom Level</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="submit_zoom">
|
||||||
|
<property name="icon-name">checkmark-symbolic</property>
|
||||||
|
<property name="tooltip-text">Zoom to Specified Level</property>
|
||||||
|
<style>
|
||||||
|
<class name="suggested-action" />
|
||||||
|
<class name="circular" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -100,4 +266,4 @@
|
||||||
<class name="image-view" />
|
<class name="image-view" />
|
||||||
</style>
|
</style>
|
||||||
</template>
|
</template>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,6 @@ mod imp {
|
||||||
#[properties(wrapper_type = super::LpWindow)]
|
#[properties(wrapper_type = super::LpWindow)]
|
||||||
#[template(file = "window.ui")]
|
#[template(file = "window.ui")]
|
||||||
pub struct LpWindow {
|
pub struct LpWindow {
|
||||||
// Template children are used with the
|
|
||||||
// TemplateChild<T> wrapper, where T is the
|
|
||||||
// object type of the template child.
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) window_content: TemplateChild<LpWindowContent>,
|
pub(super) window_content: TemplateChild<LpWindowContent>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
|
@ -92,6 +89,9 @@ mod imp {
|
||||||
pub(super) properties_button: TemplateChild<gtk::ToggleButton>,
|
pub(super) properties_button: TemplateChild<gtk::ToggleButton>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) primary_menu: TemplateChild<gtk::MenuButton>,
|
pub(super) primary_menu: TemplateChild<gtk::MenuButton>,
|
||||||
|
#[template_child]
|
||||||
|
pub(super) fullscreen_button: TemplateChild<gtk::Button>,
|
||||||
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) toast_overlay: TemplateChild<adw::ToastOverlay>,
|
pub(super) toast_overlay: TemplateChild<adw::ToastOverlay>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
|
@ -375,6 +375,22 @@ mod imp {
|
||||||
obj.schedule_hide_controls();
|
obj.schedule_hide_controls();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
obj.image_view()
|
||||||
|
.zoom_menu_button()
|
||||||
|
.connect_active_notify(glib::clone!(
|
||||||
|
#[weak]
|
||||||
|
obj,
|
||||||
|
move |button| {
|
||||||
|
if button.is_active() {
|
||||||
|
// Show overlay controls when zoom popover in them gets opened
|
||||||
|
obj.show_controls();
|
||||||
|
} else {
|
||||||
|
// Schedule hide overlay controls when zoom popover gets closed
|
||||||
|
obj.schedule_hide_controls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
// Activate global shortcuts only if no dialog is open
|
// Activate global shortcuts only if no dialog is open
|
||||||
obj.connect_visible_dialog_notify(|obj| obj.update_accel_status());
|
obj.connect_visible_dialog_notify(|obj| obj.update_accel_status());
|
||||||
obj.connect_is_active_notify(|obj| obj.update_accel_status());
|
obj.connect_is_active_notify(|obj| obj.update_accel_status());
|
||||||
|
|
@ -499,7 +515,7 @@ impl LpWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zoom_to_exact(&self, level: f64) {
|
fn zoom_to_exact(&self, level: f64) {
|
||||||
if let Some(image) = self.imp().image_view.current_image() {
|
if let Some(image) = self.image_view().current_image() {
|
||||||
image.zoom_to_exact(level);
|
image.zoom_to_exact(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -750,8 +766,9 @@ impl LpWindow {
|
||||||
Action::RotateCw,
|
Action::RotateCw,
|
||||||
Action::RotateCcw,
|
Action::RotateCcw,
|
||||||
Action::ZoomBestFit,
|
Action::ZoomBestFit,
|
||||||
Action::ZoomToExact1,
|
Action::ZoomToExact100,
|
||||||
Action::ZoomToExact2,
|
Action::ZoomToExact200,
|
||||||
|
Action::ZoomToExact300,
|
||||||
];
|
];
|
||||||
|
|
||||||
let enabled_shown = self
|
let enabled_shown = self
|
||||||
|
|
@ -780,6 +797,12 @@ impl LpWindow {
|
||||||
self.action_set_enabled(&Action::ZoomInCursor, can_zoom_in && enabled_shown);
|
self.action_set_enabled(&Action::ZoomInCursor, can_zoom_in && enabled_shown);
|
||||||
self.action_set_enabled(&Action::ZoomInCenter, can_zoom_in && enabled_shown);
|
self.action_set_enabled(&Action::ZoomInCenter, can_zoom_in && enabled_shown);
|
||||||
|
|
||||||
|
self.image_view().set_zoom_toggle_state(
|
||||||
|
self.image_view()
|
||||||
|
.current_image()
|
||||||
|
.is_some_and(|image| !image.is_best_fit()),
|
||||||
|
);
|
||||||
|
|
||||||
// Actions that are available if there is an current image, even if it's not
|
// Actions that are available if there is an current image, even if it's not
|
||||||
// shown
|
// shown
|
||||||
const ACTIONS_CURRENT: &[Action] = &[
|
const ACTIONS_CURRENT: &[Action] = &[
|
||||||
|
|
@ -944,9 +967,12 @@ impl LpWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_fullscreen_changed(&self) {
|
fn on_fullscreen_changed(&self) {
|
||||||
self.imp()
|
let icon = if self.is_fullscreen() {
|
||||||
.image_view
|
"view-restore-symbolic"
|
||||||
.on_fullscreen_changed(self.is_fullscreen());
|
} else {
|
||||||
|
"view-fullscreen-symbolic"
|
||||||
|
};
|
||||||
|
self.imp().fullscreen_button.set_icon_name(icon);
|
||||||
|
|
||||||
if !self.is_fullscreen() {
|
if !self.is_fullscreen() {
|
||||||
self.set_cursor(None);
|
self.set_cursor(None);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@
|
||||||
<attribute name="label" translatable="yes">_Open With…</attribute>
|
<attribute name="label" translatable="yes">_Open With…</attribute>
|
||||||
<attribute name="action">win.open-with</attribute>
|
<attribute name="action">win.open-with</attribute>
|
||||||
</item>
|
</item>
|
||||||
<!--<item>
|
|
||||||
<attribute name="label" translatable="yes">_Display On…</attribute>
|
|
||||||
<attribute name="action">win.display-on</attribute>
|
|
||||||
</item>-->
|
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">_Print…</attribute>
|
<attribute name="label" translatable="yes">_Print…</attribute>
|
||||||
<attribute name="action">win.print</attribute>
|
<attribute name="action">win.print</attribute>
|
||||||
|
|
@ -40,6 +36,10 @@
|
||||||
<attribute name="label" translatable="yes">_Set as Background…</attribute>
|
<attribute name="label" translatable="yes">_Set as Background…</attribute>
|
||||||
<attribute name="action">win.set-background</attribute>
|
<attribute name="action">win.set-background</attribute>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">_Delete</attribute>
|
||||||
|
<attribute name="action">win.trash</attribute>
|
||||||
|
</item>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<item>
|
<item>
|
||||||
|
|
@ -198,17 +198,10 @@
|
||||||
<class name="fullscreen-osd" />
|
<class name="fullscreen-osd" />
|
||||||
</style>
|
</style>
|
||||||
<child type="start">
|
<child type="start">
|
||||||
<object class="GtkButton">
|
<object class="GtkButton" id="fullscreen_button">
|
||||||
<property name="icon-name">edit-copy-symbolic</property>
|
<property name="halign">end</property>
|
||||||
<property name="action-name">win.copy-image</property>
|
<property name="action-name">win.toggle-fullscreen</property>
|
||||||
<property name="tooltip-text" translatable="yes">Copy to Clipboard</property>
|
<property name="tooltip-text" translatable="yes">Toggle Fullscreen</property>
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="start">
|
|
||||||
<object class="GtkButton">
|
|
||||||
<property name="icon-name">user-trash-symbolic</property>
|
|
||||||
<property name="action-name">win.trash</property>
|
|
||||||
<property name="tooltip-text" translatable="yes">Move to Trash</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child type="end">
|
<child type="end">
|
||||||
|
|
|
||||||
|
|
@ -167,10 +167,12 @@ pub enum Action {
|
||||||
ZoomInCursor,
|
ZoomInCursor,
|
||||||
#[strum(to_string = "win.zoom-best-fit")]
|
#[strum(to_string = "win.zoom-best-fit")]
|
||||||
ZoomBestFit,
|
ZoomBestFit,
|
||||||
#[strum(to_string = "win.zoom-to-exact-1")]
|
#[strum(to_string = "win.zoom-to-exact-100")]
|
||||||
ZoomToExact1,
|
ZoomToExact100,
|
||||||
#[strum(to_string = "win.zoom-to-exact-2")]
|
#[strum(to_string = "win.zoom-to-exact-200")]
|
||||||
ZoomToExact2,
|
ZoomToExact200,
|
||||||
|
#[strum(to_string = "win.zoom-to-exact-300")]
|
||||||
|
ZoomToExact300,
|
||||||
// Misc
|
// Misc
|
||||||
#[strum(to_string = "win.open")]
|
#[strum(to_string = "win.open")]
|
||||||
Open,
|
Open,
|
||||||
|
|
@ -332,7 +334,7 @@ impl Action {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::ZoomToExact1 => {
|
Action::ZoomToExact100 => {
|
||||||
klass.install_action(&action, None, move |win, _, _| {
|
klass.install_action(&action, None, move |win, _, _| {
|
||||||
win.zoom_to_exact(1.);
|
win.zoom_to_exact(1.);
|
||||||
});
|
});
|
||||||
|
|
@ -350,7 +352,7 @@ impl Action {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::ZoomToExact2 => {
|
Action::ZoomToExact200 => {
|
||||||
klass.install_action(&action, None, move |win, _, _| {
|
klass.install_action(&action, None, move |win, _, _| {
|
||||||
win.zoom_to_exact(2.);
|
win.zoom_to_exact(2.);
|
||||||
});
|
});
|
||||||
|
|
@ -368,6 +370,24 @@ impl Action {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action::ZoomToExact300 => {
|
||||||
|
klass.install_action(&action, None, move |win, _, _| {
|
||||||
|
win.zoom_to_exact(2.);
|
||||||
|
});
|
||||||
|
klass.add_binding_action(gdk::Key::_3, gdk::ModifierType::empty(), &action);
|
||||||
|
klass.add_binding_action(gdk::Key::KP_3, gdk::ModifierType::empty(), &action);
|
||||||
|
klass.add_binding_action(
|
||||||
|
gdk::Key::_3,
|
||||||
|
gdk::ModifierType::CONTROL_MASK,
|
||||||
|
&action,
|
||||||
|
);
|
||||||
|
klass.add_binding_action(
|
||||||
|
gdk::Key::KP_3,
|
||||||
|
gdk::ModifierType::CONTROL_MASK,
|
||||||
|
&action,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
Action::Open => {
|
Action::Open => {
|
||||||
klass.install_action_async(&action, None, |win, _, _| async move {
|
klass.install_action_async(&action, None, |win, _, _| async move {
|
||||||
|
|
@ -427,12 +447,13 @@ impl Action {
|
||||||
klass.install_action_async(&action, None, |win, _, _| async move {
|
klass.install_action_async(&action, None, |win, _, _| async move {
|
||||||
win.trash().await;
|
win.trash().await;
|
||||||
});
|
});
|
||||||
klass.add_binding_action(gdk::Key::Delete, gdk::ModifierType::empty(), &action);
|
|
||||||
klass.add_binding_action(
|
klass.add_binding_action(
|
||||||
gdk::Key::KP_Delete,
|
gdk::Key::KP_Delete,
|
||||||
gdk::ModifierType::empty(),
|
gdk::ModifierType::empty(),
|
||||||
&action,
|
&action,
|
||||||
);
|
);
|
||||||
|
// The binding added last is shown in menus
|
||||||
|
klass.add_binding_action(gdk::Key::Delete, gdk::ModifierType::empty(), &action);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::Delete => {
|
Action::Delete => {
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ impl LpWindow {
|
||||||
|
|
||||||
/// Start animation to hide controls
|
/// Start animation to hide controls
|
||||||
pub fn hide_controls(&self) {
|
pub fn hide_controls(&self) {
|
||||||
if self.are_controls_visible() {
|
if self.are_controls_visible() && !self.image_view().zoom_menu_button().is_active() {
|
||||||
self.show_controls_animation().pause();
|
self.show_controls_animation().pause();
|
||||||
self.hide_controls_animation()
|
self.hide_controls_animation()
|
||||||
.set_value_from(self.controls_opacity());
|
.set_value_from(self.controls_opacity());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue