properties: Remove usage of breakpoints

This commit is contained in:
Sophie Herold 2024-12-19 23:25:50 +01:00
parent 2753447a0d
commit dd359235cf
8 changed files with 210 additions and 385 deletions

View file

@ -19,6 +19,7 @@ src/metadata.rs
src/metadata/file.rs src/metadata/file.rs
src/util.rs src/util.rs
src/util/gettext.rs src/util/gettext.rs
src/util/root.rs
src/widgets.rs src/widgets.rs
src/widgets/drag_overlay.rs src/widgets/drag_overlay.rs
src/widgets/drag_overlay.ui src/widgets/drag_overlay.ui
@ -61,5 +62,3 @@ src/widgets/shy_bin.rs
src/widgets/sliding_view.rs src/widgets/sliding_view.rs
src/widgets/window.rs src/widgets/window.rs
src/widgets/window.ui src/widgets/window.ui
src/widgets/window_content.rs
src/widgets/window_content.ui

View file

@ -32,7 +32,6 @@ mod properties_view;
mod shy_bin; mod shy_bin;
mod sliding_view; mod sliding_view;
mod window; mod window;
mod window_content;
pub use drag_overlay::LpDragOverlay; pub use drag_overlay::LpDragOverlay;
pub use edit_window::LpEditWindow; pub use edit_window::LpEditWindow;
@ -47,4 +46,3 @@ pub use properties_view::LpPropertiesView;
pub use shy_bin::LpShyBin; pub use shy_bin::LpShyBin;
pub use sliding_view::LpSlidingView; pub use sliding_view::LpSlidingView;
pub use window::LpWindow; pub use window::LpWindow;
pub use window_content::LpWindowContent;

View file

@ -45,7 +45,7 @@ use crate::util::gettext::*;
use crate::util::root::ParentWindow; use crate::util::root::ParentWindow;
use crate::util::Direction; use crate::util::Direction;
use crate::widgets::window::ActionPartGlobal; use crate::widgets::window::ActionPartGlobal;
use crate::widgets::{LpDragOverlay, LpImage, LpImageView, LpPropertiesView, LpWindowContent}; use crate::widgets::{LpDragOverlay, LpImage, LpImageView, LpPropertiesView};
/// Animation duration for showing overlay buttons in milliseconds /// Animation duration for showing overlay buttons in milliseconds
const SHOW_CONTROLS_ANIMATION_DURATION: u32 = 200; const SHOW_CONTROLS_ANIMATION_DURATION: u32 = 200;
@ -61,9 +61,6 @@ mod imp {
#[properties(wrapper_type = super::LpImageWindow)] #[properties(wrapper_type = super::LpImageWindow)]
#[template(file = "image_window.ui")] #[template(file = "image_window.ui")]
pub struct LpImageWindow { pub struct LpImageWindow {
#[template_child]
pub(super) window_content: TemplateChild<LpWindowContent>,
#[template_child] #[template_child]
pub(super) headerbar: TemplateChild<adw::HeaderBar>, pub(super) headerbar: TemplateChild<adw::HeaderBar>,
#[template_child] #[template_child]
@ -77,6 +74,9 @@ mod imp {
#[template_child] #[template_child]
pub(super) primary_menu: TemplateChild<gtk::MenuButton>, pub(super) primary_menu: TemplateChild<gtk::MenuButton>,
#[template_child]
pub(super) toolbar_view: TemplateChild<adw::ToolbarView>,
#[template_child] #[template_child]
pub(super) stack: TemplateChild<gtk::Stack>, pub(super) stack: TemplateChild<gtk::Stack>,
#[template_child] #[template_child]
@ -98,9 +98,6 @@ mod imp {
#[property(get = Self::is_showing_image)] #[property(get = Self::is_showing_image)]
pub(super) is_showing_image: PhantomData<bool>, pub(super) is_showing_image: PhantomData<bool>,
/// Set via binding to HeaderBar
#[property(get, set)]
headerbar_opacity: Cell<f64>,
/// Motion controller for complete window /// Motion controller for complete window
pub(super) motion_controller: gtk::EventControllerMotion, pub(super) motion_controller: gtk::EventControllerMotion,
@ -293,6 +290,18 @@ mod imp {
), ),
); );
obj.connect_is_showing_image_notify(|obj| {
obj.update_headerbar_style();
});
self.properties_button.connect_active_notify(glib::clone!(
#[weak]
obj,
move |_| {
obj.update_headerbar_style();
}
));
// action win.previous status // action win.previous status
self.image_view self.image_view
.connect_is_previous_available_notify(glib::clone!( .connect_is_previous_available_notify(glib::clone!(
@ -880,6 +889,8 @@ impl LpImageWindow {
}; };
self.imp().fullscreen_button.set_icon_name(icon); self.imp().fullscreen_button.set_icon_name(icon);
self.update_headerbar_style();
if !self.window().is_fullscreen() { if !self.window().is_fullscreen() {
self.set_cursor(None); self.set_cursor(None);
self.show_controls(); self.show_controls();
@ -888,11 +899,14 @@ impl LpImageWindow {
} }
fn is_headerbar_flat(&self) -> bool { fn is_headerbar_flat(&self) -> bool {
self.imp().window_content.is_headerbar_flat() matches!(
self.imp().toolbar_view.top_bar_style(),
adw::ToolbarStyle::Flat
)
} }
fn is_content_extended_to_top(&self) -> bool { fn is_content_extended_to_top(&self) -> bool {
self.imp().window_content.is_content_extended_to_top() self.window().is_fullscreen() && !self.imp().properties_button.is_active()
} }
fn update_accel_status(&self) { fn update_accel_status(&self) {
@ -917,4 +931,39 @@ impl LpImageWindow {
pub fn properties_button(&self) -> gtk::ToggleButton { pub fn properties_button(&self) -> gtk::ToggleButton {
self.imp().properties_button.clone() self.imp().properties_button.clone()
} }
fn update_header_opacity(&self) {
let imp = self.imp();
if self.is_headerbar_flat() && self.is_showing_image() {
// Bring headerbar opacity in sync with controls
imp.headerbar.set_opacity(self.headerbar_opacity());
} else {
imp.headerbar.set_opacity(1.);
}
}
fn update_headerbar_style(&self) {
let imp = self.imp();
imp.toolbar_view
.set_extend_content_to_top_edge(self.is_content_extended_to_top());
let style = if !self.is_showing_image() || self.is_content_extended_to_top() {
// Flat headerbar for empty state and fullscreen without properties enabled
adw::ToolbarStyle::Flat
} else {
// Use the border variant of raised to avoid shadows over images
adw::ToolbarStyle::RaisedBorder
};
if style != imp.toolbar_view.top_bar_style() {
imp.toolbar_view.set_top_bar_style(style);
self.update_header_opacity();
}
}
fn headerbar_opacity(&self) -> f64 {
self.imp().headerbar.opacity()
}
} }

View file

@ -58,126 +58,21 @@
</menu> </menu>
<template class="LpImageWindow" parent="AdwBin"> <template class="LpImageWindow" parent="AdwBin">
<property name="child"> <property name="child">
<object class="AdwMultiLayoutView" id="multi_layout_view"> <object class="AdwToolbarView" id="toolbar_view">
<child>
<object class="AdwLayout">
<property name="name">sidebar-properies</property>
<property name="content">
<object class="LpWindowContent" id="window_content">
<property name="show-properties" bind-source="properties_button" bind-property="active" bind-flags="sync-create|invert-boolean" />
<property name="headerbar">
<object class="AdwLayoutSlot">
<property name="id">headerbar</property>
</object>
</property>
<property name="content">
<object class="AdwOverlaySplitView" id="properties_split_view">
<property name="sidebar-position">end</property>
<property name="min-sidebar-width">255</property>
<property name="show-sidebar" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create" />
<property name="content">
<object class="AdwLayoutSlot">
<property name="id">content</property>
</object>
</property>
<property name="sidebar">
<object class="AdwLayoutSlot">
<property name="id">properties</property>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</child>
<child>
<object class="AdwLayout">
<property name="name">bottom-properties</property>
<property name="content">
<object class="LpWindowContent">
<property name="show-properties" bind-source="properties_button" bind-property="active" bind-flags="sync-create|invert-boolean" />
<property name="headerbar">
<object class="AdwLayoutSlot">
<property name="id">headerbar</property>
</object>
</property>
<property name="content">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="AdwLayoutSlot">
<property name="id">content</property>
<property name="vexpand">True</property>
</object>
</child>
<child>
<object class="GtkRevealer">
<property name="transition-type">slide-up</property>
<property name="reveal-child" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create" />
<style>
<class name="bottom-properties" />
</style>
<property name="child">
<object class="AdwLayoutSlot">
<property name="id">properties</property>
</object>
</property>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
<child>
<object class="AdwLayout">
<property name="name">overlay-properties</property>
<property name="content">
<object class="AdwBottomSheet">
<property name="modal">True</property>
<property name="open" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create" />
<property name="content">
<object class="LpWindowContent">
<property name="show-properties" bind-source="properties_button" bind-property="active" bind-flags="sync-create|invert-boolean" />
<property name="headerbar">
<object class="AdwLayoutSlot">
<property name="id">headerbar</property>
</object>
</property>
<property name="content">
<object class="AdwLayoutSlot">
<property name="id">content</property>
</object>
</property>
</object>
</property>
<property name="sheet">
<object class="AdwToolbarView">
<child type="top"> <child type="top">
<object class="AdwHeaderBar"> <object class="LpShyBin">
<property name="show-title">False</property> <property name="child">
</object>
</child>
<property name="content">
<object class="AdwLayoutSlot">
<property name="id">properties</property>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</child>
<!-- Layout slots -->
<child type="headerbar">
<object class="AdwHeaderBar" id="headerbar"> <object class="AdwHeaderBar" id="headerbar">
<!-- <binding name="show-end-title-buttons">
<property name="show-end-title-buttons" bind-source="window" bind-property="fullscreened" bind-flags="sync-create|invert-boolean" /> <lookup name="not-fullscreened" type="LpWindow">
<property name="show-start-title-buttons" bind-source="window" bind-property="fullscreened" bind-flags="sync-create|invert-boolean" /> <lookup name="root">LpImageWindow</lookup>
--> </lookup>
</binding>
<binding name="show-start-title-buttons">
<lookup name="not-fullscreened" type="LpWindow">
<lookup name="root">LpImageWindow</lookup>
</lookup>
</binding>
<style> <style>
<class name="fullscreen-osd" /> <class name="fullscreen-osd" />
</style> </style>
@ -236,9 +131,73 @@
<object class="GtkEventControllerMotion" id="headerbar_events" /> <object class="GtkEventControllerMotion" id="headerbar_events" />
</child> </child>
</object> </object>
</property>
</object>
</child>
<property name="content">
<object class="AdwMultiLayoutView">
<binding name="layout-name">
<lookup name="layout-name" type="LpWindow">
<lookup name="root">LpImageWindow</lookup>
</lookup>
</binding>
<child>
<object class="AdwLayout">
<property name="name">wide</property>
<property name="content">
<object class="AdwOverlaySplitView" id="properties_split_view">
<property name="sidebar-position">end</property>
<property name="min-sidebar-width">255</property>
<property name="show-sidebar" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create" />
<property name="sidebar">
<object class="AdwLayoutSlot">
<property name="id">properties</property>
</object>
</property>
<property name="content">
<object class="AdwLayoutSlot">
<property name="id">content</property>
</object>
</property>
</object>
</property>
</object>
</child>
<child>
<object class="AdwLayout">
<property name="name">narrow</property>
<property name="content">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="AdwLayoutSlot">
<property name="id">content</property>
</object>
</child>
<child>
<object class="GtkRevealer">
<property name="transition-type">slide-up</property>
<property name="reveal-child" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create" />
<style>
<class name="bottom-properties" />
</style>
<property name="child">
<object class="AdwLayoutSlot">
<property name="id">properties</property>
</object>
</property>
</object>
</child>
</object>
</property>
</object>
</child>
<child type="properties">
<object class="LpPropertiesView" id="properties_view" />
</child> </child>
<child type="content"> <child type="content">
<object class="LpDragOverlay" id="drag_overlay"> <object class="LpDragOverlay" id="drag_overlay">
<property name="vexpand">true</property>
<property name="drop_target">drop_target</property> <property name="drop_target">drop_target</property>
<property name="content"> <property name="content">
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
@ -287,9 +246,8 @@
</property> </property>
</object> </object>
</child> </child>
<child type="properties"> </object>
<object class="LpPropertiesView" id="properties_view" /> </property>
</child>
</object> </object>
</property> </property>
</template> </template>

View file

@ -34,7 +34,7 @@ use crate::widgets::{LpEditWindow, LpImageView, LpImageWindow};
const SHOW_WINDOW_AFTER: u64 = 2000; const SHOW_WINDOW_AFTER: u64 = 2000;
mod imp { mod imp {
use std::cell::Cell; use std::cell::{Cell, RefCell};
use super::*; use super::*;
@ -70,6 +70,10 @@ mod imp {
narrow_layout: Cell<bool>, narrow_layout: Cell<bool>,
#[property(get, set)] #[property(get, set)]
wide_layout: Cell<bool>, wide_layout: Cell<bool>,
#[property(get, set)]
layout_name: RefCell<String>,
#[property(get, set)]
not_fullscreened: Cell<bool>,
} }
#[glib::object_subclass] #[glib::object_subclass]

View file

@ -5,18 +5,23 @@
<property name="default-height">498</property> <property name="default-height">498</property>
<property name="width-request">360</property> <property name="width-request">360</property>
<property name="height-request">294</property> <property name="height-request">294</property>
<property name="layout-name">wide</property>
<property name="wide-layout" bind-source="LpWindow" bind-property="narrow-layout" bind-flags="sync-create|invert-boolean" />
<property name="not-fullscreened" bind-source="LpWindow" bind-property="fullscreened" bind-flags="sync-create|invert-boolean" />
<child> <child>
<object class="AdwBreakpoint"> <object class="AdwBreakpoint">
<condition>min-width: 590sp</condition> <condition>min-width: 590sp</condition>
<setter object="LpWindow" property="layout-name">wide</setter>
<setter object="LpWindow" property="narrow-layout">false</setter> <setter object="LpWindow" property="narrow-layout">false</setter>
<setter object="LpWindow" property="wide-layout">true</setter>
</object> </object>
</child> </child>
<child> <child>
<object class="AdwBreakpoint"> <object class="AdwBreakpoint">
<condition>max-width: 590sp</condition> <condition>max-width: 590sp</condition>
<setter object="LpWindow" property="layout-name">narrow</setter>
<setter object="LpWindow" property="narrow-layout">true</setter> <setter object="LpWindow" property="narrow-layout">true</setter>
<setter object="LpWindow" property="wide-layout">false</setter>
</object> </object>
</child> </child>
<property name="content"> <property name="content">

View file

@ -1,161 +0,0 @@
// Copyright (c) 2024 Sophie Herold
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Copyright (c) 2024 Christopher Davis
//! Contains the main structure inside the window
//!
//! This is it's own widget since it's reused inside different layouts for
//! different positions of the image properties.
use std::cell::{Cell, RefCell};
use adw::prelude::*;
use adw::subclass::prelude::*;
use glib::Properties;
use gtk::CompositeTemplate;
use crate::deps::*;
mod imp {
use super::*;
#[derive(Default, Debug, Properties, CompositeTemplate)]
#[properties(wrapper_type = super::LpWindowContent)]
#[template(file = "window_content.ui")]
pub struct LpWindowContent {
#[template_child]
pub(super) toolbar_view: TemplateChild<adw::ToolbarView>,
#[property(get, set, nullable)]
headerbar: RefCell<Option<gtk::Widget>>,
#[property(get, set, nullable)]
content: RefCell<Option<gtk::Widget>>,
// Set via binding to window
#[property(get, set)]
fullscreened: Cell<bool>,
// Set via binding to properties toggle button
#[property(get, set)]
show_properties: Cell<bool>,
// Set via binding to window
#[property(get, set)]
is_showing_image: Cell<bool>,
}
impl LpWindowContent {
fn update_header_opacity(&self) {
let obj = self.obj();
if let Some(headerbar) = obj.headerbar() {
if obj.is_headerbar_flat() && obj.is_showing_image() {
// Bring headerbar opacity in sync with controls
headerbar.set_opacity(self.headerbar_opacity());
} else {
headerbar.set_opacity(1.);
};
}
}
fn update_headerbar_style(&self) {
let obj = self.obj();
self.toolbar_view
.set_extend_content_to_top_edge(obj.is_content_extended_to_top());
let style = if !obj.is_showing_image() || obj.is_content_extended_to_top() {
// Flat headerbar for empty state and fullscreen without properties enabled
adw::ToolbarStyle::Flat
} else {
// Use the border variant of raised to avoid shadows over images
adw::ToolbarStyle::RaisedBorder
};
let toolbar_view = self.toolbar_view.get();
if style != toolbar_view.top_bar_style() {
toolbar_view.set_top_bar_style(style);
self.update_header_opacity();
}
}
fn headerbar_opacity(&self) -> f64 {
self.headerbar
.borrow()
.as_ref()
.map(|x| x.opacity())
.unwrap_or(1.)
}
}
#[glib::object_subclass]
impl ObjectSubclass for LpWindowContent {
const NAME: &'static str = "LpWindowContent";
type Type = super::LpWindowContent;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
}
fn instance_init(obj: &gio::glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for LpWindowContent {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
obj.connect_is_showing_image_notify(|obj| {
obj.imp().update_headerbar_style();
});
obj.connect_fullscreened_notify(|obj| {
obj.imp().update_headerbar_style();
});
obj.connect_show_properties_notify(|obj| {
obj.imp().update_headerbar_style();
});
}
}
impl WidgetImpl for LpWindowContent {}
impl BinImpl for LpWindowContent {}
}
glib::wrapper! {
pub struct LpWindowContent(ObjectSubclass<imp::LpWindowContent>)
@extends gtk::Widget, adw::Bin,
@implements gtk::Buildable, gtk::ConstraintTarget;
}
impl LpWindowContent {
pub fn is_headerbar_flat(&self) -> bool {
matches!(
self.imp().toolbar_view.top_bar_style(),
adw::ToolbarStyle::Flat
)
}
pub fn is_content_extended_to_top(&self) -> bool {
self.fullscreened() && self.show_properties()
}
}

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="LpWindowContent" parent="AdwBin">
<binding name="fullscreened">
<lookup name="fullscreened" type="GtkWindow">
<lookup name="root">LpWindowContent</lookup>
</lookup>
</binding>
<!--
<binding name="is-showing-image">
<lookup name="is-showing-image" type="LpWindow">
<lookup name="root">LpWindowContent</lookup>
</lookup>
</binding>
-->
<property name="child">
<object class="AdwToolbarView" id="toolbar_view">
<child type="top">
<object class="LpShyBin">
<property name="child" bind-source="LpWindowContent" bind-property="headerbar" />
</object>
</child>
<property name="content" bind-source="LpWindowContent" bind-property="content" />
</object>
</property>
</template>
</interface>