libcosmic/examples/cosmic/src/window/demo.rs
Michael Aaron Murphy b3d550cc5e feat!(segmented-button): improved interfaces and documentation
BREAKING CHANGE: Various type and function names have changed to reflect
themselves better in documentation. Code has been reorganized into
separate modules with a better placement in libcosmic. Most of the
functions, types, and modules now have documentation and examples.

These changes no longer require the `Model` type to define the
data/component type that it stores. The component functionality is now
optional, and it's also possible to associate many components to an item
with one component per type. This has had a side effect of simplifying a
lot of the type signatures in the implementation.

Before, to insert an item into the model, you had to define a
`SegmentedItem` and a `Component` on insert, and get back an ID for that
item. Which makes it difficult to define an item that contains only an
icon or has no components. And requires an extra insert function to
activate the item on insert.

Now, there is a flexible builder-style API for configuring
newly-inserted items in the model. So the complexity for inserting and
retrieving values from the model has decreased significantly
2023-01-19 19:58:31 +01:00

341 lines
15 KiB
Rust

use apply::Apply;
use cosmic::{
iced::widget::{checkbox, pick_list, progress_bar, radio, row, slider},
iced::{widget::container, Alignment, Length},
theme::{Button as ButtonTheme, Theme},
widget::{
button, segmented_button, segmented_selection, settings,
spin_button::{SpinButtonModel, SpinMessage},
toggler, view_switcher,
},
Element,
};
use super::{Page, Window};
pub enum DemoView {
TabA,
TabB,
TabC,
}
#[allow(dead_code)]
pub enum MultiOption {
OptionA,
OptionB,
OptionC,
OptionD,
OptionE,
}
#[derive(Clone, Copy, Debug)]
pub enum Message {
ButtonPressed,
CheckboxToggled(bool),
Debug(bool),
IconTheme(segmented_button::Entity),
MultiSelection(segmented_button::Entity),
PickListSelected(&'static str),
RowSelected(usize),
Selection(segmented_button::Entity),
SliderChanged(f32),
SpinButton(SpinMessage),
ThemeChanged(Theme),
TogglerToggled(bool),
ViewSwitcher(segmented_button::Entity),
}
pub enum Output {
Debug(bool),
ThemeChanged(Theme),
}
pub struct State {
pub checkbox_value: bool,
pub icon_themes: segmented_button::SingleSelectModel,
pub multi_selection: segmented_button::MultiSelectModel,
pub pick_list_selected: Option<&'static str>,
pub pick_list_options: Vec<&'static str>,
pub selection: segmented_button::SingleSelectModel,
pub slider_value: f32,
pub spin_button: SpinButtonModel<i32>,
pub toggler_value: bool,
pub view_switcher: segmented_button::SingleSelectModel,
}
impl Default for State {
fn default() -> State {
State {
checkbox_value: false,
pick_list_selected: Some("Option 1"),
pick_list_options: vec!["Option 1", "Option 2", "Option 3", "Option 4"],
slider_value: 50.0,
spin_button: SpinButtonModel::default().min(-10).max(10),
toggler_value: false,
icon_themes: segmented_button::Model::builder()
.insert(|b| b.text("Pop").activate())
.insert(|b| b.text("Adwaita"))
.build(),
selection: segmented_button::Model::builder()
.insert(|b| b.text("Choice A").activate())
.insert(|b| b.text("Choice B"))
.insert(|b| b.text("Choice C"))
.build(),
multi_selection: segmented_button::Model::builder()
.insert(|b| b.text("Option A").data(MultiOption::OptionA).activate())
.insert(|b| b.text("Option B").data(MultiOption::OptionB))
.insert(|b| b.text("Option C").data(MultiOption::OptionC))
.insert(|b| b.text("Option D").data(MultiOption::OptionD))
.insert(|b| b.text("Option E").data(MultiOption::OptionE))
.build(),
view_switcher: segmented_button::Model::builder()
.insert(|b| b.text("Controls").data(DemoView::TabA).activate())
.insert(|b| b.text("Segmented Button").data(DemoView::TabB))
.insert(|b| b.text("Tab C").data(DemoView::TabC))
.build(),
}
}
}
impl State {
pub(super) fn update(&mut self, message: Message) -> Option<Output> {
match message {
Message::ButtonPressed => (),
Message::CheckboxToggled(value) => self.checkbox_value = value,
Message::Debug(value) => return Some(Output::Debug(value)),
Message::PickListSelected(value) => self.pick_list_selected = Some(value),
Message::RowSelected(row) => println!("Selected row {row}"),
Message::MultiSelection(key) => self.multi_selection.activate(key),
Message::Selection(key) => self.selection.activate(key),
Message::SliderChanged(value) => self.slider_value = value,
Message::SpinButton(msg) => self.spin_button.update(msg),
Message::ThemeChanged(theme) => return Some(Output::ThemeChanged(theme)),
Message::TogglerToggled(value) => self.toggler_value = value,
Message::ViewSwitcher(key) => self.view_switcher.activate(key),
Message::IconTheme(key) => {
self.icon_themes.activate(key);
if let Some(theme) = self.icon_themes.text(key) {
cosmic::settings::set_default_icon_theme(theme);
}
}
}
None
}
pub(super) fn view<'a>(&'a self, window: &'a Window) -> Element<'a, Message> {
let choose_theme = [Theme::Light, Theme::Dark].iter().fold(
row![].spacing(10).align_items(Alignment::Center),
|row, theme| {
row.push(radio(
format!("{:?}", theme),
*theme,
Some(window.theme),
Message::ThemeChanged,
))
},
);
let choose_icon_theme =
segmented_selection::horizontal(&self.icon_themes).on_activate(Message::IconTheme);
settings::view_column(vec![
window.page_title(Page::Demo),
view_switcher::horizontal(&self.view_switcher)
.on_activate(Message::ViewSwitcher)
.into(),
match self.view_switcher.active_data() {
None => panic!("no tab is active"),
Some(DemoView::TabA) => settings::view_column(vec![
settings::view_section("Debug")
.add(settings::item("Debug theme", choose_theme))
.add(settings::item("Debug icon theme", choose_icon_theme))
.add(settings::item(
"Debug layout",
toggler(None, window.debug, Message::Debug),
))
.into(),
settings::view_section("Buttons")
.add(settings::item_row(vec![
button(ButtonTheme::Primary)
.text("Primary")
.on_press(Message::ButtonPressed)
.into(),
button(ButtonTheme::Secondary)
.text("Secondary")
.on_press(Message::ButtonPressed)
.into(),
button(ButtonTheme::Positive)
.text("Positive")
.on_press(Message::ButtonPressed)
.into(),
button(ButtonTheme::Destructive)
.text("Destructive")
.on_press(Message::ButtonPressed)
.into(),
button(ButtonTheme::Text)
.text("Text")
.on_press(Message::ButtonPressed)
.into(),
]))
.add(settings::item_row(vec![
button(ButtonTheme::Primary).text("Primary").into(),
button(ButtonTheme::Secondary).text("Secondary").into(),
button(ButtonTheme::Positive).text("Positive").into(),
button(ButtonTheme::Destructive).text("Destructive").into(),
button(ButtonTheme::Text).text("Text").into(),
]))
.into(),
settings::view_section("Controls")
.add(settings::item(
"Toggler",
toggler(None, self.toggler_value, Message::TogglerToggled),
))
.add(settings::item(
"Pick List (TODO)",
pick_list(
&self.pick_list_options,
self.pick_list_selected,
Message::PickListSelected,
)
.padding([8, 0, 8, 16]),
))
.add(settings::item(
"Slider",
slider(0.0..=100.0, self.slider_value, Message::SliderChanged)
.width(Length::Units(250)),
))
.add(settings::item(
"Progress",
progress_bar(0.0..=100.0, self.slider_value)
.width(Length::Units(250))
.height(Length::Units(4)),
))
.add(settings::item_row(vec![checkbox(
"Checkbox",
self.checkbox_value,
Message::CheckboxToggled,
)
.into()]))
.add(settings::item(
format!(
"Spin Button (Range {}:{})",
self.spin_button.min, self.spin_button.max
),
self.spin_button.view(Message::SpinButton),
))
.into(),
])
.padding(0)
.into(),
Some(DemoView::TabB) => settings::view_column(vec![
cosmic::iced::widget::text("Selection")
.font(cosmic::font::FONT_SEMIBOLD)
.into(),
cosmic::iced::widget::text("Horizontal").into(),
segmented_selection::horizontal(&self.selection)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Horizontal With Spacing").into(),
segmented_selection::horizontal(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Horizontal Multi-Select").into(),
segmented_selection::horizontal(&self.multi_selection)
.spacing(8)
.on_activate(Message::MultiSelection)
.into(),
cosmic::iced::widget::text("Vertical").into(),
segmented_selection::vertical(&self.selection)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Vertical Multi-Select Shrunk").into(),
segmented_selection::vertical(&self.multi_selection)
.width(Length::Shrink)
.on_activate(Message::MultiSelection)
.apply(container)
.center_x()
.width(Length::Fill)
.into(),
cosmic::iced::widget::text("Vertical With Spacing").into(),
cosmic::iced::widget::row(vec![
segmented_selection::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
segmented_selection::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
segmented_selection::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
])
.spacing(12)
.width(Length::Fill)
.into(),
cosmic::iced::widget::text("View Switcher")
.font(cosmic::font::FONT_SEMIBOLD)
.into(),
cosmic::iced::widget::text("Horizontal").into(),
view_switcher::horizontal(&self.selection)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Horizontal Multi-Select").into(),
view_switcher::horizontal(&self.multi_selection)
.on_activate(Message::MultiSelection)
.into(),
cosmic::iced::widget::text("Horizontal With Spacing").into(),
view_switcher::horizontal(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Vertical").into(),
view_switcher::vertical(&self.selection)
.on_activate(Message::Selection)
.into(),
cosmic::iced::widget::text("Vertical Multi-Select").into(),
view_switcher::vertical(&self.multi_selection)
.on_activate(Message::MultiSelection)
.into(),
cosmic::iced::widget::text("Vertical With Spacing").into(),
cosmic::iced::widget::row(vec![
view_switcher::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
view_switcher::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
view_switcher::vertical(&self.selection)
.spacing(8)
.on_activate(Message::Selection)
.width(Length::FillPortion(1))
.into(),
])
.spacing(12)
.width(Length::Fill)
.into(),
])
.padding(0)
.into(),
Some(DemoView::TabC) => {
settings::view_column(vec![settings::view_section("Tab C")
.add(cosmic::iced::widget::text("Nothing here yet").width(Length::Fill))
.into()])
.padding(0)
.into()
}
},
])
.into()
}
}