From 8e6959a3cb4fa0ac69393d274e9418d0954eca7d Mon Sep 17 00:00:00 2001 From: Eduardo Flores Date: Sat, 15 Oct 2022 15:08:44 -0700 Subject: [PATCH] View Switcher Widget --- examples/cosmic/src/window.rs | 4 +- src/widget/view_switcher.rs | 89 +++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/widget/view_switcher.rs diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 0d4cfc37..41f46aa4 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -9,7 +9,7 @@ use cosmic::{ iced_lazy::responsive, iced_winit::window::{drag, toggle_maximize, minimize}, theme::{self, Theme}, - widget::{button, nav_button, nav_bar, nav_bar_page, nav_bar_section, header_bar, settings, scrollable, toggler}, + widget::{button, nav_button, nav_bar, header_bar, settings, scrollable, toggler}, Element, ElementExt, }; @@ -62,6 +62,7 @@ pub enum Message { TogglerToggled(bool), PickListSelected(&'static str), RowSelected(usize), + ViewChanged(usize), Close, ToggleSidebar, Drag, @@ -110,6 +111,7 @@ impl Application for Window { Message::Minimize => return minimize(true), Message::Maximize => return toggle_maximize(), Message::RowSelected(row) => println!("Selected row {row}"), + Message::ViewChanged(view) => println!("Selected view {view}"), } Command::none() diff --git a/src/widget/view_switcher.rs b/src/widget/view_switcher.rs new file mode 100644 index 00000000..7cfe240e --- /dev/null +++ b/src/widget/view_switcher.rs @@ -0,0 +1,89 @@ +use derive_setters::Setters; +use iced::{ + alignment::{Horizontal, Vertical}, + theme, + widget::{button, container, text, Row}, + Background, Element, Length, Renderer, Theme, Alignment, +}; +use iced_lazy::Component; + +#[derive(Setters)] +pub struct ViewSwitcher<'a, Message> { + options: Vec<&'a str>, + #[setters(strip_option)] + on_view_changed: Option Message + 'a>> +} + +pub fn view_switcher<'a, Message>() -> ViewSwitcher<'a, Message> { + ViewSwitcher { options: vec![], on_view_changed: None } +} + +#[derive(Clone)] +pub enum ViewSwitcherEvent { + ViewSelected(usize), +} + +#[derive(Default)] +pub struct ViewSwitcherState { + selected_view: usize, +} + +impl<'a, Message> Component for ViewSwitcher<'a, Message> { + type State = ViewSwitcherState; + + type Event = ViewSwitcherEvent; + + fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option { + match event { + ViewSwitcherEvent::ViewSelected(index) => state.selected_view = index, + } + self.on_view_changed.as_ref().map(|on_view_changed| (on_view_changed)(state.selected_view)) + } + + fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer> { + let mut options: Vec> = vec![]; + + for (index, option) in self.options.iter().enumerate() { + options.push( + button( + container(text(option)) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center), + ) + .width(Length::Fill) + .height(Length::Units(32)) + .style(if state.selected_view == index { + theme::Button::Secondary.into() + } else { + theme::Button::Primary.into() + }) + .on_press(ViewSwitcherEvent::ViewSelected(index)) + .into(), + ); + } + container(Row::with_children(options).align_items(Alignment::Fill)) + .width(Length::Fill) + .padding(2) + .style(theme::Container::Custom(view_switcher_container_style)) + .into() + } +} + +pub fn view_switcher_container_style(theme: &Theme) -> iced_style::container::Appearance { + let accent = &theme.cosmic().accent; + iced_style::container::Appearance { + text_color: Default::default(), + background: Some(Background::Color(accent.base.into())), + border_radius: 24.0, + border_width: 2.0, + border_color: accent.base.into(), + } +} + +impl<'a, Message: 'a> From> for Element<'a, Message> { + fn from(view_switcher: ViewSwitcher<'a, Message>) -> Self { + iced_lazy::component(view_switcher) + } +}