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
This commit is contained in:
parent
095e4c1acd
commit
b3d550cc5e
22 changed files with 1097 additions and 675 deletions
|
|
@ -115,7 +115,7 @@ pub struct Window {
|
|||
checkbox_value: bool,
|
||||
toggler_value: bool,
|
||||
pick_list_selected: Option<&'static str>,
|
||||
nav_bar_pages: segmented_button::SingleSelectModel<Page>,
|
||||
nav_bar_pages: segmented_button::SingleSelectModel,
|
||||
nav_bar_toggled_condensed: bool,
|
||||
nav_bar_toggled: bool,
|
||||
show_minimize: bool,
|
||||
|
|
@ -126,18 +126,12 @@ pub struct Window {
|
|||
|
||||
impl Window {
|
||||
/// Adds a page to the model we use for the navigation bar.
|
||||
fn insert_page(&mut self, page: Page) -> segmented_button::Key {
|
||||
self.nav_bar_pages.insert(
|
||||
segmented_button::item()
|
||||
.text(page.title())
|
||||
.icon(IconSource::Name(page.icon_name().into())),
|
||||
page,
|
||||
)
|
||||
}
|
||||
|
||||
/// Activates the page by its key.
|
||||
fn activate_page(&mut self, page: segmented_button::Key) {
|
||||
self.nav_bar_pages.activate(page);
|
||||
fn insert_page(&mut self, page: Page) -> segmented_button::SingleSelectEntityMut {
|
||||
self.nav_bar_pages
|
||||
.insert()
|
||||
.text(page.title())
|
||||
.icon(IconSource::Name(page.icon_name().into()))
|
||||
.data(page)
|
||||
}
|
||||
|
||||
fn is_condensed(&self) -> bool {
|
||||
|
|
@ -185,7 +179,7 @@ pub enum Message {
|
|||
Maximize,
|
||||
InputChanged,
|
||||
Rectangle(RectangleUpdate<u32>),
|
||||
NavBar(segmented_button::Key),
|
||||
NavBar(segmented_button::Entity),
|
||||
}
|
||||
|
||||
impl Application for Window {
|
||||
|
|
@ -208,7 +202,7 @@ impl Application for Window {
|
|||
window.insert_page(Page::WiFi);
|
||||
window.insert_page(Page::Networking);
|
||||
window.insert_page(Page::Bluetooth);
|
||||
let key = window.insert_page(Page::Desktop);
|
||||
window.insert_page(Page::Desktop).activate();
|
||||
window.insert_page(Page::InputDevices);
|
||||
window.insert_page(Page::Displays);
|
||||
window.insert_page(Page::PowerAndBattery);
|
||||
|
|
@ -219,7 +213,6 @@ impl Application for Window {
|
|||
window.insert_page(Page::TimeAndLanguage);
|
||||
window.insert_page(Page::Accessibility);
|
||||
window.insert_page(Page::Applications);
|
||||
window.activate_page(key);
|
||||
|
||||
(window, Command::none())
|
||||
}
|
||||
|
|
@ -231,7 +224,7 @@ impl Application for Window {
|
|||
fn update(&mut self, message: Message) -> iced::Command<Self::Message> {
|
||||
match message {
|
||||
Message::NavBar(key) => {
|
||||
if let Some(page) = self.nav_bar_pages.component(key).cloned() {
|
||||
if let Some(page) = self.nav_bar_pages.data::<Page>(key).cloned() {
|
||||
self.nav_bar_pages.activate(key);
|
||||
self.page(page);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ pub struct Window {
|
|||
debug: bool,
|
||||
demo: demo::State,
|
||||
desktop: desktop::State,
|
||||
nav_bar_pages: segmented_button::SingleSelectModel<Page>,
|
||||
nav_bar: segmented_button::SingleSelectModel,
|
||||
nav_id_to_page: segmented_button::SecondaryMap<Page>,
|
||||
nav_bar_toggled_condensed: bool,
|
||||
nav_bar_toggled: bool,
|
||||
page: Page,
|
||||
|
|
@ -178,7 +179,7 @@ pub enum Message {
|
|||
KeyboardNav(keyboard_nav::Message),
|
||||
Maximize,
|
||||
Minimize,
|
||||
NavBar(segmented_button::Key),
|
||||
NavBar(segmented_button::Entity),
|
||||
Page(Page),
|
||||
ToggleNavBar,
|
||||
ToggleNavBarCondensed,
|
||||
|
|
@ -193,18 +194,12 @@ impl From<Page> for Message {
|
|||
|
||||
impl Window {
|
||||
/// Adds a page to the model we use for the navigation bar.
|
||||
fn insert_page(&mut self, page: Page) -> segmented_button::Key {
|
||||
self.nav_bar_pages.insert(
|
||||
segmented_button::item()
|
||||
.text(page.title())
|
||||
.icon(IconSource::Name(page.icon_name().into())),
|
||||
page,
|
||||
)
|
||||
}
|
||||
|
||||
/// Activates the page by its key.
|
||||
fn activate_page(&mut self, page: segmented_button::Key) {
|
||||
self.nav_bar_pages.activate(page);
|
||||
fn insert_page(&mut self, page: Page) -> segmented_button::SingleSelectEntityMut {
|
||||
self.nav_bar
|
||||
.insert()
|
||||
.text(page.title())
|
||||
.icon(IconSource::Name(page.icon_name().into()))
|
||||
.secondary(&mut self.nav_id_to_page, page)
|
||||
}
|
||||
|
||||
fn page_title<Message: 'static>(&self, page: Page) -> Element<Message> {
|
||||
|
|
@ -313,7 +308,7 @@ impl Application for Window {
|
|||
window.insert_page(Page::WiFi);
|
||||
window.insert_page(Page::Networking(None));
|
||||
window.insert_page(Page::Bluetooth);
|
||||
let key = window.insert_page(Page::Desktop(None));
|
||||
window.insert_page(Page::Desktop(None)).activate();
|
||||
window.insert_page(Page::InputDevices(None));
|
||||
window.insert_page(Page::Displays);
|
||||
window.insert_page(Page::PowerAndBattery);
|
||||
|
|
@ -324,7 +319,6 @@ impl Application for Window {
|
|||
window.insert_page(Page::TimeAndLanguage(None));
|
||||
window.insert_page(Page::Accessibility);
|
||||
window.insert_page(Page::Applications);
|
||||
window.activate_page(key);
|
||||
|
||||
(window, Command::none())
|
||||
}
|
||||
|
|
@ -363,8 +357,8 @@ impl Application for Window {
|
|||
let mut ret = Command::none();
|
||||
match message {
|
||||
Message::NavBar(key) => {
|
||||
if let Some(page) = self.nav_bar_pages.component(key).cloned() {
|
||||
self.nav_bar_pages.activate(key);
|
||||
if let Some(page) = self.nav_id_to_page.get(key).copied() {
|
||||
self.nav_bar.activate(key);
|
||||
self.page(page);
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +431,7 @@ impl Application for Window {
|
|||
let mut widgets = Vec::with_capacity(2);
|
||||
|
||||
if nav_bar_toggled {
|
||||
let mut nav_bar = nav_bar(&self.nav_bar_pages, Message::NavBar);
|
||||
let mut nav_bar = nav_bar(&self.nav_bar, Message::NavBar);
|
||||
|
||||
if !self.is_condensed() {
|
||||
nav_bar = nav_bar.max_width(300);
|
||||
|
|
|
|||
|
|
@ -4,17 +4,9 @@ use cosmic::{
|
|||
iced::{widget::container, Alignment, Length},
|
||||
theme::{Button as ButtonTheme, Theme},
|
||||
widget::{
|
||||
button,
|
||||
segmented_button::{
|
||||
self,
|
||||
cosmic::{
|
||||
horizontal_segmented_selection, horizontal_view_switcher,
|
||||
vertical_segmented_selection, vertical_view_switcher,
|
||||
},
|
||||
},
|
||||
settings,
|
||||
button, segmented_button, segmented_selection, settings,
|
||||
spin_button::{SpinButtonModel, SpinMessage},
|
||||
toggler,
|
||||
toggler, view_switcher,
|
||||
},
|
||||
Element,
|
||||
};
|
||||
|
|
@ -41,16 +33,16 @@ pub enum Message {
|
|||
ButtonPressed,
|
||||
CheckboxToggled(bool),
|
||||
Debug(bool),
|
||||
IconTheme(segmented_button::Key),
|
||||
MultiSelection(segmented_button::Key),
|
||||
IconTheme(segmented_button::Entity),
|
||||
MultiSelection(segmented_button::Entity),
|
||||
PickListSelected(&'static str),
|
||||
RowSelected(usize),
|
||||
Selection(segmented_button::Key),
|
||||
Selection(segmented_button::Entity),
|
||||
SliderChanged(f32),
|
||||
SpinButton(SpinMessage),
|
||||
ThemeChanged(Theme),
|
||||
TogglerToggled(bool),
|
||||
ViewSwitcher(segmented_button::Key),
|
||||
ViewSwitcher(segmented_button::Entity),
|
||||
}
|
||||
|
||||
pub enum Output {
|
||||
|
|
@ -60,15 +52,15 @@ pub enum Output {
|
|||
|
||||
pub struct State {
|
||||
pub checkbox_value: bool,
|
||||
pub icon_theme: segmented_button::SingleSelectModel<&'static str>,
|
||||
pub multi_selection: segmented_button::MultiSelectModel<MultiOption>,
|
||||
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 selection: segmented_button::SingleSelectModel,
|
||||
pub slider_value: f32,
|
||||
pub spin_button: SpinButtonModel<i32>,
|
||||
pub toggler_value: bool,
|
||||
pub view_switcher: segmented_button::SingleSelectModel<DemoView>,
|
||||
pub view_switcher: segmented_button::SingleSelectModel,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
|
|
@ -80,26 +72,26 @@ impl Default for State {
|
|||
slider_value: 50.0,
|
||||
spin_button: SpinButtonModel::default().min(-10).max(10),
|
||||
toggler_value: false,
|
||||
icon_theme: segmented_button::Model::builder()
|
||||
.insert_active("Pop", "Pop")
|
||||
.insert("Adwaita", "Adwaita")
|
||||
icon_themes: segmented_button::Model::builder()
|
||||
.insert(|b| b.text("Pop").activate())
|
||||
.insert(|b| b.text("Adwaita"))
|
||||
.build(),
|
||||
selection: segmented_button::Model::builder()
|
||||
.insert_active("Choice A", ())
|
||||
.insert("Choice B", ())
|
||||
.insert("Choice C", ())
|
||||
.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_active("Option A", MultiOption::OptionA)
|
||||
.insert("Option B", MultiOption::OptionB)
|
||||
.insert("Option C", MultiOption::OptionB)
|
||||
.insert("Option D", MultiOption::OptionC)
|
||||
.insert("Option E", MultiOption::OptionE)
|
||||
.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_active("Controls", DemoView::TabA)
|
||||
.insert("Segmented Button", DemoView::TabB)
|
||||
.insert("Tab C", DemoView::TabC)
|
||||
.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(),
|
||||
}
|
||||
}
|
||||
|
|
@ -121,9 +113,9 @@ impl State {
|
|||
Message::TogglerToggled(value) => self.toggler_value = value,
|
||||
Message::ViewSwitcher(key) => self.view_switcher.activate(key),
|
||||
Message::IconTheme(key) => {
|
||||
self.icon_theme.activate(key);
|
||||
if let Some(theme) = self.icon_theme.component(key) {
|
||||
cosmic::settings::set_default_icon_theme(*theme);
|
||||
self.icon_themes.activate(key);
|
||||
if let Some(theme) = self.icon_themes.text(key) {
|
||||
cosmic::settings::set_default_icon_theme(theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -145,14 +137,14 @@ impl State {
|
|||
);
|
||||
|
||||
let choose_icon_theme =
|
||||
horizontal_segmented_selection(&self.icon_theme).on_activate(Message::IconTheme);
|
||||
segmented_selection::horizontal(&self.icon_themes).on_activate(Message::IconTheme);
|
||||
|
||||
settings::view_column(vec![
|
||||
window.page_title(Page::Demo),
|
||||
horizontal_view_switcher(&self.view_switcher)
|
||||
view_switcher::horizontal(&self.view_switcher)
|
||||
.on_activate(Message::ViewSwitcher)
|
||||
.into(),
|
||||
match self.view_switcher.active_component() {
|
||||
match self.view_switcher.active_data() {
|
||||
None => panic!("no tab is active"),
|
||||
Some(DemoView::TabA) => settings::view_column(vec![
|
||||
settings::view_section("Debug")
|
||||
|
|
@ -241,25 +233,25 @@ impl State {
|
|||
.font(cosmic::font::FONT_SEMIBOLD)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal").into(),
|
||||
horizontal_segmented_selection(&self.selection)
|
||||
segmented_selection::horizontal(&self.selection)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal With Spacing").into(),
|
||||
horizontal_segmented_selection(&self.selection)
|
||||
segmented_selection::horizontal(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal Multi-Select").into(),
|
||||
horizontal_segmented_selection(&self.multi_selection)
|
||||
segmented_selection::horizontal(&self.multi_selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::MultiSelection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Vertical").into(),
|
||||
vertical_segmented_selection(&self.selection)
|
||||
segmented_selection::vertical(&self.selection)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Vertical Multi-Select Shrunk").into(),
|
||||
vertical_segmented_selection(&self.multi_selection)
|
||||
segmented_selection::vertical(&self.multi_selection)
|
||||
.width(Length::Shrink)
|
||||
.on_activate(Message::MultiSelection)
|
||||
.apply(container)
|
||||
|
|
@ -268,17 +260,17 @@ impl State {
|
|||
.into(),
|
||||
cosmic::iced::widget::text("Vertical With Spacing").into(),
|
||||
cosmic::iced::widget::row(vec![
|
||||
vertical_segmented_selection(&self.selection)
|
||||
segmented_selection::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
.into(),
|
||||
vertical_segmented_selection(&self.selection)
|
||||
segmented_selection::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
.into(),
|
||||
vertical_segmented_selection(&self.selection)
|
||||
segmented_selection::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
|
|
@ -291,39 +283,39 @@ impl State {
|
|||
.font(cosmic::font::FONT_SEMIBOLD)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal").into(),
|
||||
horizontal_view_switcher(&self.selection)
|
||||
view_switcher::horizontal(&self.selection)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal Multi-Select").into(),
|
||||
horizontal_view_switcher(&self.multi_selection)
|
||||
view_switcher::horizontal(&self.multi_selection)
|
||||
.on_activate(Message::MultiSelection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Horizontal With Spacing").into(),
|
||||
horizontal_view_switcher(&self.selection)
|
||||
view_switcher::horizontal(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Vertical").into(),
|
||||
vertical_view_switcher(&self.selection)
|
||||
view_switcher::vertical(&self.selection)
|
||||
.on_activate(Message::Selection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Vertical Multi-Select").into(),
|
||||
vertical_view_switcher(&self.multi_selection)
|
||||
view_switcher::vertical(&self.multi_selection)
|
||||
.on_activate(Message::MultiSelection)
|
||||
.into(),
|
||||
cosmic::iced::widget::text("Vertical With Spacing").into(),
|
||||
cosmic::iced::widget::row(vec![
|
||||
vertical_view_switcher(&self.selection)
|
||||
view_switcher::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
.into(),
|
||||
vertical_view_switcher(&self.selection)
|
||||
view_switcher::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
.into(),
|
||||
vertical_view_switcher(&self.selection)
|
||||
view_switcher::vertical(&self.selection)
|
||||
.spacing(8)
|
||||
.on_activate(Message::Selection)
|
||||
.width(Length::FillPortion(1))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue