diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 5769b870..e23ceeea 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -9,7 +9,7 @@ use cosmic::{ theme::{self, Theme}, widget::{ header_bar, icon, list, nav_bar, nav_bar_toggle, scrollable, segmented_button, settings, - IconSource, + warning, IconSource, }, Element, ElementExt, }; @@ -140,6 +140,7 @@ pub struct Window { system_and_accounts: system_and_accounts::State, theme: Theme, title: String, + show_warning: bool, } impl Window { @@ -157,6 +158,11 @@ impl Window { self.show_minimize = show; self } + + pub fn show_warning(mut self, show: bool) -> Self { + self.show_warning = show; + self + } } #[allow(dead_code)] @@ -176,6 +182,7 @@ pub enum Message { Page(Page), ToggleNavBar, ToggleNavBarCondensed, + CloseWarning, } impl From for Message { @@ -297,7 +304,8 @@ impl Application for Window { let mut window = Window::default() .nav_bar_toggled(true) .show_maximize(true) - .show_minimize(true); + .show_minimize(true) + .show_warning(true); window.title = String::from("COSMIC Design System - Iced"); @@ -390,6 +398,7 @@ impl Application for Window { keyboard_nav::Message::FocusNext => ret = widget::focus_next(), keyboard_nav::Message::FocusPrevious => ret = widget::focus_previous(), }, + Message::CloseWarning => self.show_warning = false, } ret } @@ -515,8 +524,14 @@ impl Application for Window { .width(Length::Fill) .height(Length::Fill) .into(); - - column(vec![header, content]).into() + let warning = warning("This is a warning") + .on_close(Message::CloseWarning) + .into(); + if self.show_warning { + column(vec![header, warning, content]).into() + } else { + column(vec![header, content]).into() + } } fn theme(&self) -> Theme { diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 05a9ff01..9682fb2b 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -41,3 +41,6 @@ pub use spin_button::{spin_button, SpinButton}; pub mod rectangle_tracker; pub mod aspect_ratio; + +pub mod warning; +pub use warning::*; diff --git a/src/widget/warning.rs b/src/widget/warning.rs new file mode 100644 index 00000000..764a87b6 --- /dev/null +++ b/src/widget/warning.rs @@ -0,0 +1,75 @@ +// Copyright 2022 System76 +// SPDX-License-Identifier: MPL-2.0 + +use std::borrow::Cow; + +use iced::{alignment, widget, Alignment, Background, Color, Length}; + +use crate::{theme, Element, Renderer, Theme}; + +use super::icon; + +#[must_use] +pub fn warning<'a, Message>(message: impl Into>) -> Warning<'a, Message> { + Warning { + message: message.into(), + on_close: None, + } +} + +pub struct Warning<'a, Message> { + message: Cow<'a, str>, + on_close: Option, +} + +impl<'a, Message: 'static + Clone> Warning<'a, Message> { + /// The message to emit on button press. + #[must_use] + pub fn on_close(mut self, message: Message) -> Self { + self.on_close = Some(message); + self + } + + /// A custom button that has the desired default spacing and padding. + pub fn into_widget(self) -> widget::Container<'static, Message, Renderer> { + let close_button = + widget::button(icon("window-close-symbolic", 16).style(theme::Svg::Default)) + .style(theme::Button::Transparent); + + let close_button = if let Some(message) = self.on_close { + close_button.on_press(message) + } else { + close_button + }; + + widget::container( + widget::row(vec![ + widget::container(widget::text(self.message)) + .width(Length::Fill) + .into(), + close_button.into(), + ]) + .align_items(Alignment::Center), + ) + .style(theme::Container::Custom(warning_container)) + .padding(10) + .align_y(alignment::Vertical::Center) + .width(Length::Fill) + } +} + +impl<'a, Message: 'static + Clone> From> for Element<'a, Message> { + fn from(warning: Warning<'a, Message>) -> Self { + Self::from(warning.into_widget()) + } +} + +pub fn warning_container(theme: &Theme) -> widget::container::Appearance { + widget::container::Appearance { + text_color: Some(theme.cosmic().on_warning_color().into()), + background: Some(Background::Color(theme.cosmic().warning_color().into())), + border_radius: 0.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + } +}