diff --git a/src/app/mod.rs b/src/app/mod.rs index b713e7c..b9166e6 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -71,13 +71,6 @@ use { zbus::{interface, proxy, zvariant::Value}, }; -#[cfg(feature = "desktop")] -use { - crate::widget, - iced::{alignment::Vertical, Alignment}, - std::collections::BTreeMap, -}; - pub(crate) fn iced_settings( settings: Settings, flags: App::Flags, @@ -470,6 +463,16 @@ where Vec::new() } + /// Non-scrolling elements placed below the context drawer title row + fn context_drawer_header(&self) -> Option>> { + None + } + + /// Elements placed below the context drawer scrollable + fn context_drawer_footer(&self) -> Option>> { + None + } + /// Displays a dialog in the center of the application window when `Some`. fn dialog(&self) -> Option> { None @@ -752,6 +755,8 @@ impl ApplicationExt for App { context_drawer( &core.window.context_title, self.context_header_actions(), + self.context_drawer_header(), + self.context_drawer_footer(), Message::Cosmic(cosmic::Message::ContextDrawer(false)), main_content, context.map(Message::App), @@ -786,6 +791,8 @@ impl ApplicationExt for App { crate::widget::ContextDrawer::new_inner( &core.window.context_title, self.context_header_actions(), + self.context_drawer_header(), + self.context_drawer_footer(), context.map(Message::App), Message::Cosmic(cosmic::Message::ContextDrawer(false)), context_width, diff --git a/src/widget/about.rs b/src/widget/about.rs index 8e45833..a5bd0b3 100644 --- a/src/widget/about.rs +++ b/src/widget/about.rs @@ -1,7 +1,7 @@ #[cfg(feature = "desktop")] use { crate::{ - iced::{alignment::Vertical, Alignment, Length}, + iced::{Alignment, Length}, widget::{self, horizontal_space}, Element, }, @@ -124,7 +124,11 @@ pub fn about<'a, Message: Clone + 'static>( about: &'a About, on_url_press: impl Fn(String) -> Message, ) -> Element<'a, Message> { - let spacing = crate::theme::active().cosmic().spacing; + let cosmic_theme::Spacing { + space_xxs, + space_xs, + .. + } = crate::theme::active().cosmic().spacing; let section = |list: &'a Vec<(String, String)>, title: &'a str| { (!list.is_empty()).then_some({ @@ -138,8 +142,8 @@ pub fn about<'a, Message: Clone + 'static>( .push_maybe((!url.is_empty()).then_some( crate::widget::icon::from_name("link-symbolic").icon(), )) - .padding(spacing.space_xxs) - .align_y(Vertical::Center), + .padding(space_xxs) + .align_y(Alignment::Center), ) .class(crate::theme::Button::Text) .on_press(on_url_press(url.clone())) @@ -176,8 +180,8 @@ pub fn about<'a, Message: Clone + 'static>( url.is_some() .then_some(crate::widget::icon::from_name("link-symbolic").icon()), ) - .padding(spacing.space_xxs) - .align_y(Vertical::Center), + .padding(space_xxs) + .align_y(Alignment::Center), ) .class(crate::theme::Button::Text) .on_press(on_url_press(url.unwrap_or(String::new()))) @@ -187,25 +191,22 @@ pub fn about<'a, Message: Clone + 'static>( let copyright = about.copyright.as_ref().map(widget::text::body); let comments = about.comments.as_ref().map(widget::text::body); - widget::scrollable( - widget::column() - .push_maybe(application_icon) - .push_maybe(application_name) - .push_maybe(author) - .push_maybe(version) - .push_maybe(license) - .push_maybe(links_section) - .push_maybe(developers_section) - .push_maybe(designers_section) - .push_maybe(artists_section) - .push_maybe(translators_section) - .push_maybe(documenters_section) - .push_maybe(comments) - .push_maybe(copyright) - .align_x(Alignment::Center) - .spacing(spacing.space_xs) - .width(Length::Fill), - ) - .spacing(spacing.space_xxxs) - .into() + widget::column() + .push_maybe(application_icon) + .push_maybe(application_name) + .push_maybe(author) + .push_maybe(version) + .push_maybe(license) + .push_maybe(links_section) + .push_maybe(developers_section) + .push_maybe(designers_section) + .push_maybe(artists_section) + .push_maybe(translators_section) + .push_maybe(documenters_section) + .push_maybe(comments) + .push_maybe(copyright) + .align_x(Alignment::Center) + .spacing(space_xs) + .width(Length::Fill) + .into() } diff --git a/src/widget/context_drawer/mod.rs b/src/widget/context_drawer/mod.rs index 0581a21..5a90fc8 100644 --- a/src/widget/context_drawer/mod.rs +++ b/src/widget/context_drawer/mod.rs @@ -13,7 +13,9 @@ use crate::Element; /// An overlayed widget that attaches a toggleable context drawer to the view. pub fn context_drawer<'a, Message: Clone + 'static, Content, Drawer>( title: &'a str, - actions: Vec>, + header_actions: Vec>, + header_opt: Option>, + footer_opt: Option>, on_close: Message, content: Content, drawer: Drawer, @@ -23,5 +25,14 @@ where Content: Into>, Drawer: Into>, { - ContextDrawer::new(title, actions, content, drawer, on_close, max_width) + ContextDrawer::new( + title, + header_actions, + header_opt, + footer_opt, + content, + drawer, + on_close, + max_width, + ) } diff --git a/src/widget/context_drawer/widget.rs b/src/widget/context_drawer/widget.rs index ea4aa3c..759749f 100644 --- a/src/widget/context_drawer/widget.rs +++ b/src/widget/context_drawer/widget.rs @@ -1,7 +1,7 @@ // Copyright 2023 System76 // SPDX-License-Identifier: MPL-2.0 -use crate::widget::{button, column, container, icon, row, text, LayerContainer}; +use crate::widget::{button, column, container, icon, row, scrollable, text, LayerContainer}; use crate::{Apply, Element, Renderer, Theme}; use super::overlay::Overlay; @@ -25,7 +25,9 @@ pub struct ContextDrawer<'a, Message> { impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { pub fn new_inner( title: &'a str, - actions: Vec>, + header_actions: Vec>, + header_opt: Option>, + footer_opt: Option>, drawer: Drawer, on_close: Message, max_width: f32, @@ -35,6 +37,8 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { { let cosmic_theme::Spacing { space_xxs, + space_xs, + space_s, space_m, space_l, .. @@ -46,12 +50,13 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { Some(text::heading(title).width(Length::FillPortion(1)).center()) }; - let header = row::with_capacity(3) + let horizontal_padding = if max_width < 392.0 { space_s } else { space_l }; + + let header_row = row::with_capacity(3) .width(Length::Fixed(480.0)) .align_y(Alignment::Center) - .padding([space_m, space_l]) .push( - row::with_children(actions) + row::with_children(header_actions) .spacing(space_xxs) .width(Length::FillPortion(1)), ) @@ -64,12 +69,32 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { .width(Length::FillPortion(1)) .align_x(Alignment::End), ); - - let pane = column::with_capacity(2).push(header).push( - container(drawer.into()) + let header = column::with_capacity(2) + .width(Length::Fixed(480.0)) + .align_x(Alignment::Center) + .spacing(space_m) + .padding([space_m, horizontal_padding]) + .push(header_row) + .push_maybe(header_opt); + let footer = footer_opt.map(|element| { + container(element) + .width(Length::Fixed(480.0)) + .align_y(Alignment::Center) + .padding([space_xs, horizontal_padding]) + }); + let pane = column::with_capacity(3) + .push(header) + .push( + scrollable(container(drawer.into()).padding([ + 0, + horizontal_padding, + if footer.is_some() { 0 } else { space_l }, + horizontal_padding, + ])) .height(Length::Fill) .width(Length::Shrink), - ); + ) + .push_maybe(footer); // XXX new limits do not exactly handle the max width well for containers // XXX this is a hack to get around that @@ -90,7 +115,9 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { /// Creates an empty [`ContextDrawer`]. pub fn new( title: &'a str, - actions: Vec>, + header_actions: Vec>, + header_opt: Option>, + footer_opt: Option>, content: Content, drawer: Drawer, on_close: Message, @@ -100,7 +127,15 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> { Content: Into>, Drawer: Into>, { - let drawer = Self::new_inner(title, actions, drawer, on_close, max_width); + let drawer = Self::new_inner( + title, + header_actions, + header_opt, + footer_opt, + drawer, + on_close, + max_width, + ); ContextDrawer { id: None,