diff --git a/examples/cosmic/src/window/demo.rs b/examples/cosmic/src/window/demo.rs index 0f07200c..5209fb82 100644 --- a/examples/cosmic/src/window/demo.rs +++ b/examples/cosmic/src/window/demo.rs @@ -2,7 +2,7 @@ use cosmic::{ iced::widget::{checkbox, pick_list, progress_bar, radio, row, slider}, iced::{Alignment, Length}, theme::{self, Button as ButtonTheme, Theme}, - widget::{button, segmented_button, settings, toggler}, + widget::{button, segmented_button::cosmic::{view_switcher, segmented_selection}, settings, toggler}, Element, }; @@ -30,8 +30,7 @@ impl Window { settings::view_column(vec![ self.page_title(Page::Demo), - segmented_button(&self.demo_view_switcher) - .height(Length::Units(48)) + view_switcher(&self.demo_view_switcher) .on_activate(Message::DemoTabActivate) .into(), match self.demo_view_switcher.active_data() { @@ -122,8 +121,7 @@ impl Window { cosmic::iced::widget::text("SegmentedButton::Selection") .font(cosmic::font::FONT_SEMIBOLD) .into(), - segmented_button(&self.demo_selection) - .style(theme::SegmentedButton::Selection) + segmented_selection(&self.demo_selection) .on_activate(Message::DemoSelectionActivate) .into() ]) diff --git a/src/widget/segmented_button/cosmic.rs b/src/widget/segmented_button/cosmic.rs new file mode 100644 index 00000000..2557c44b --- /dev/null +++ b/src/widget/segmented_button/cosmic.rs @@ -0,0 +1,29 @@ +// Copyright 2022 System76 +// SPDX-License-Identifier: MPL-2.0 + +use super::{SegmentedButton, State}; +use iced_core::Length; + +/// Appears as a collection of tabs for developing a tabbed interface. +/// +/// The data for the widget comes from a [`State`] that is maintained the application. +#[must_use] +pub fn view_switcher( + state: &State, +) -> SegmentedButton { + SegmentedButton::new(&state.inner) + .height(Length::Units(48)) + .style(crate::theme::SegmentedButton::ViewSwitcher) +} + +/// Appears as a selection of choices for choosing between. +/// +/// The data for the widget comes from a [`State`] that is maintained the application. +#[must_use] +pub fn segmented_selection( + state: &State, +) -> SegmentedButton { + SegmentedButton::new(&state.inner) + .height(Length::Units(32)) + .style(crate::theme::SegmentedButton::Selection) +} diff --git a/src/widget/segmented_button/mod.rs b/src/widget/segmented_button/mod.rs index 9922ef94..389d56c1 100644 --- a/src/widget/segmented_button/mod.rs +++ b/src/widget/segmented_button/mod.rs @@ -1,5 +1,49 @@ -/// Copyright 2022 System76 +// Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 + +//! A widget providing a conjoined set of linear buttons for choosing between. +//! +//! ## Example +//! +//! Add the state and a message variant in your application for handling selections. +//! +//! ```no_run +//! use iced_core::Length; +//! use cosmic::theme; +//! use cosmic::widget::segmented_button; +//! +//! enum AppMessage { +//! Selected(segmented_button::Key) +//! } +//! +//! struct App { +//! ... +//! state: segmented_button::State(), +//! ... +//! } +//! ``` +//! +//! Then add choices to the state, while activating the first. +//! +//! ```no_run +//! let first_key = application.state.insert("Choice A", 0); +//! application.state.insert("Choice B", 1); +//! application.state.insert("Choice C", 2); +//! application.state.activate(first_key); +//! ``` +//! +//! Then use it in the view method to create segmented button widgets. +//! +//! ```no_run +//! let widget = segmentend_button(&application.state) +//! .style(theme::SegmentedButton::Selection) +//! .height(Length::Units(32)) +//! .on_activate(AppMessage::Selected); +//! ``` + +/// COSMIC configurations of [`SegmentedButton`]. +pub mod cosmic; + mod state; mod style; @@ -22,19 +66,28 @@ struct PrivateWidgetState { hovered: Key, } -/// A linear set of options for choosing between. +/// A widget providing a conjoined set of linear buttons for choosing between. +/// +/// The data for the widget comes from a [`State`] that is maintained the application. #[derive(Setters)] pub struct SegmentedButton<'a, Message, Renderer> where Renderer: iced_native::Renderer, Renderer::Theme: StyleSheet, { + /// Contains application state also used for drawing. + #[setters(skip)] state: &'a WidgetState, + /// The desired width of the widget. width: Length, + /// The desired height of the widget. height: Length, + /// The desired spacing between widgets. spacing: u16, + /// The style to draw the widget in. #[setters(into)] style: ::Style, + /// Emits the ID of the activated widget on selection. #[setters(skip)] on_activate: Option Message>>, } @@ -56,6 +109,7 @@ where } } + /// Emits the ID of the activated widget on selection. #[must_use] pub fn on_activate(mut self, on_activate: impl Fn(Key) -> Message + 'static) -> Self { self.on_activate = Some(Box::from(on_activate)); @@ -63,6 +117,7 @@ where } } +/// Creates a widget that presents multiple conjoined buttons. #[must_use] pub fn segmented_button( state: &State, diff --git a/src/widget/segmented_button/state.rs b/src/widget/segmented_button/state.rs index 80dcf67b..58819f1e 100644 --- a/src/widget/segmented_button/state.rs +++ b/src/widget/segmented_button/state.rs @@ -1,17 +1,20 @@ -/// Copyright 2022 System76 +// Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 + use slotmap::{SecondaryMap, SlotMap}; use std::borrow::Cow; -use crate::theme::Button; - slotmap::new_key_type! { + /// An ID for a segmented button pub struct Key; } -/// Contains all state for interacting with a [`SegmentedButton`]. +/// Contains all state for interacting with a segmented button. pub struct State { + /// State that is shared with widget drawing. pub inner: WidgetState, + + /// State unique to the application. pub data: SecondaryState, } @@ -27,7 +30,10 @@ impl Default for State { /// State which is most useful to the widget. #[derive(Default)] pub struct WidgetState { + /// The content used for drawing segmented buttons. pub buttons: SlotMap, + + /// The actively-selected segmented button. pub active: Key, } @@ -72,7 +78,7 @@ impl State { } } -/// Data to be drawn in a [`SegmentedButton`] button. +/// Data to be drawn in a segmented button. pub struct ButtonContent { pub text: Cow<'static, str>, } diff --git a/src/widget/segmented_button/style.rs b/src/widget/segmented_button/style.rs index 8d7eb53d..35f76a35 100644 --- a/src/widget/segmented_button/style.rs +++ b/src/widget/segmented_button/style.rs @@ -1,8 +1,9 @@ -/// Copyright 2022 System76 +// Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 + use iced_core::{Background, BorderRadius, Color}; -/// The appearance of a [`SegmentedButton`]. +/// The appearance of a segmented button. #[derive(Clone, Copy)] pub struct Appearance { pub background: Option, @@ -14,7 +15,7 @@ pub struct Appearance { pub button_hover: ButtonAppearance, } -/// The appearance of a button in the [`SegmentedButton`] +/// The appearance of a button in the segmented button #[derive(Clone, Copy)] pub struct ButtonAppearance { pub background: Option, @@ -25,11 +26,11 @@ pub struct ButtonAppearance { pub text_color: Color, } -/// Defines the [`Appearance`] of a [`SegmentedButton`]. +/// Defines the [`Appearance`] of a segmented button. pub trait StyleSheet { /// The supported style of the [`StyleSheet`]. type Style: Default; - /// The [`Appearance`] of the [`SegmentedButton`]. + /// The [`Appearance`] of the segmented button. fn appearance(&self, style: &Self::Style) -> Appearance; }