diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 41f46aa4..cacba0ca 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, header_bar, settings, scrollable, toggler}, + widget::{button, nav_button, nav_bar, header_bar, settings, scrollable, toggler, nav_bar_item, view_switcher}, Element, ElementExt, }; @@ -145,61 +145,61 @@ impl Application for Window { let content = responsive(|size| { let condensed = size.width < 900.0; let sidebar: Element<_> = nav_bar() - .source(BTreeMap::from([ - ( + .source(BTreeMap::from([ + ( + nav_bar_item() + .title("Network & Wireless") + .icon("nm-device-wired"), + vec![nav_bar_item().title("Wi-Fi").icon("network-wireless")], + ), + ( + nav_bar_item().title("Bluetooth").icon("cs-bluetooth"), + vec![nav_bar_item().title("Devices").icon("computer")], + ), + ( + nav_bar_item() + .title("Personalization") + .icon("applications-system"), + vec![ nav_bar_item() - .title("Network & Wireless") - .icon("nm-device-wired"), - vec![nav_bar_item().title("Wi-Fi").icon("network-wireless")], - ), - ( - nav_bar_item().title("Bluetooth").icon("cs-bluetooth"), - vec![nav_bar_item().title("Devices").icon("computer")], - ), - ( + .title("Desktop Session") + .icon("desktop-panel"), nav_bar_item() - .title("Personalization") - .icon("applications-system"), - vec![ - nav_bar_item() - .title("Desktop Session") - .icon("desktop-panel"), - nav_bar_item() - .title("Wallpaper") - .icon("preferences-desktop-wallpaper"), - nav_bar_item().title("Appearance").icon("cs-color"), - nav_bar_item() - .title("Dock & Top Panel") - .icon("desktop-panel"), - nav_bar_item() - .title("Workspaces") - .icon("preferences-system-windows"), - nav_bar_item() - .title("Notifications") - .icon("cs-notifications"), - ], - ), - ( - nav_bar_item().title("Input Devices").icon("input-keyboard"), - vec![nav_bar_item().title("Keyboard").icon("computer")], - ), - ( - nav_bar_item().title("Displays").icon("cs-display"), - vec![nav_bar_item().title("External Monitors").icon("computer")], - ), - ( - nav_bar_item().title("Power & Battery").icon("battery"), - vec![nav_bar_item().title("Status").icon("computer")], - ), - ( - nav_bar_item().title("Sound").icon("sound"), - vec![nav_bar_item().title("Volume").icon("computer")], - ), - ])) - .on_page_selected(Box::new(Message::Page)) - .active(self.sidebar_toggled) - .condensed(condensed) - .into(); + .title("Wallpaper") + .icon("preferences-desktop-wallpaper"), + nav_bar_item().title("Appearance").icon("cs-color"), + nav_bar_item() + .title("Dock & Top Panel") + .icon("desktop-panel"), + nav_bar_item() + .title("Workspaces") + .icon("preferences-system-windows"), + nav_bar_item() + .title("Notifications") + .icon("cs-notifications"), + ], + ), + ( + nav_bar_item().title("Input Devices").icon("input-keyboard"), + vec![nav_bar_item().title("Keyboard").icon("computer")], + ), + ( + nav_bar_item().title("Displays").icon("cs-display"), + vec![nav_bar_item().title("External Monitors").icon("computer")], + ), + ( + nav_bar_item().title("Power & Battery").icon("battery"), + vec![nav_bar_item().title("Status").icon("computer")], + ), + ( + nav_bar_item().title("Sound").icon("sound"), + vec![nav_bar_item().title("Volume").icon("computer")], + ), + ])) + .on_page_selected(Box::new(Message::Page)) + .active(self.sidebar_toggled) + .condensed(condensed) + .into(); let choose_theme = [Theme::Light, Theme::Dark].iter().fold( row![].spacing(10).align_items(Alignment::Center), @@ -274,6 +274,11 @@ impl Application for Window { .width(Length::Units(250)) .height(Length::Units(4)) )) + .into(), + settings::view_section("View Switcher") + .add(view_switcher() + .options(vec!["Details", "Identity", "IPv4", "IPv6", "Security"]) + .on_view_changed(Box::new(Message::ViewChanged))) .into() ]) .into(); diff --git a/src/widget/mod.rs b/src/widget/mod.rs index f1940c37..29212db5 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -29,3 +29,6 @@ pub use scrollable::*; pub mod separator; pub use separator::{horizontal_rule, vertical_rule}; + +pub mod view_switcher; +pub use view_switcher::*; \ No newline at end of file diff --git a/src/widget/navigation/macros.rs b/src/widget/navigation/macros.rs index e9ae13cb..b34e1204 100644 --- a/src/widget/navigation/macros.rs +++ b/src/widget/navigation/macros.rs @@ -20,9 +20,9 @@ pub mod nav_bar { .align_items($crate::iced::alignment::Alignment::Center), ) .style(if $active { - $crate::iced::theme::Button::Primary.into() + $crate::theme::Button::Primary } else { - $crate::iced::theme::Button::Text.into() + $crate::theme::Button::Text }) } else { $crate::iced::widget::Button::new( @@ -34,9 +34,9 @@ pub mod nav_bar { ) .padding(10) .style(if $active { - $crate::iced::theme::Button::Primary.into() + $crate::theme::Button::Primary } else { - $crate::iced::theme::Button::Text.into() + $crate::theme::Button::Text }) } }; diff --git a/src/widget/navigation/navbar.rs b/src/widget/navigation/navbar.rs index d3fbf4cc..fa30eb93 100644 --- a/src/widget/navigation/navbar.rs +++ b/src/widget/navigation/navbar.rs @@ -1,16 +1,17 @@ // Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 +use crate::Renderer; use crate::widget::nav_bar::{nav_bar_pages_style, nav_bar_sections_style}; use crate::widget::{icon, scrollable}; -use crate::{theme, Renderer, Theme}; -use derive_setters::Setters; -use iced::{Background, Length}; -use iced_lazy::Component; -use iced_native::widget::{button, column, container, text}; -use iced_native::{row, Alignment, Element}; -use iced_style::button::Appearance; +use crate::iced::{Length, Background}; +use crate::iced_lazy::Component; +use crate::iced::widget::{button, column, container, text}; +use crate::iced_native::{row, Alignment, Element}; +use crate::iced_style::button::Appearance; +use crate::{theme, Theme}; use std::collections::BTreeMap; +use derive_setters::Setters; #[derive(Setters, Default)] pub struct NavBar<'a, Message> { @@ -93,71 +94,111 @@ impl<'a, Message> Component for NavBar<'a, Message> { fn view(&self, state: &Self::State) -> Element { if self.active { - let mut sections: Vec> = vec![]; - let mut pages: Vec> = vec![]; + let mut sections: Vec> = vec![]; + let mut pages: Vec> = vec![]; for (section_index, (section, section_pages)) in self.source.iter().enumerate() { sections.push( - crate::nav_button!( - §ion.title, - §ion.icon, - true, - section_index == state.selected_section + button( + column(vec![ + icon(§ion.icon, 20).into(), + text(§ion.title).size(14).into(), + ]) + .width(Length::Units(100)) + .height(Length::Units(50)) + .align_items(Alignment::Center), ) + .style(if section_index == state.selected_section { + theme::Button::Primary.into() + } else { + theme::Button::Text.into() + }) .on_press(NavBarEvent::SectionSelected(section_index)) .into(), ); if section_index == state.selected_section { for (page_index, page) in section_pages.iter().enumerate() { - let active = state.selected_page.is_some() - && page_index == state.selected_page.unwrap(); - pages.push( - crate::nav_button!(&page.title, &page.icon, self.condensed, active) - .on_press(NavBarEvent::PageSelected(section_index, page_index)) - .into(), - ); + pages.push(if self.condensed { + button( + column(vec![ + icon(&page.icon, 20).into(), + text(&page.title).size(14).into(), + ]) + .width(Length::Units(100)) + .height(Length::Units(50)) + .align_items(Alignment::Center), + ) + .style(if let Some(selected_page) = state.selected_page { + if page_index == selected_page { + theme::Button::Primary.into() + } else { + theme::Button::Text.into() + } + } else { + theme::Button::Text.into() + }).on_press(NavBarEvent::PageSelected(section_index, page_index)) + .into() + } else { + button(row![ + icon(&page.icon, 20), + text(&page.title).size(16).width(Length::Fill) + ].spacing(10)) + .padding(10) + .style(if let Some(selected_page) = state.selected_page { + if page_index == selected_page { + theme::Button::Primary.into() + } else { + theme::Button::Text.into() + } + } else { + theme::Button::Text.into() + }) + .on_press(NavBarEvent::PageSelected(section_index, page_index)) + .into() + }); } } } - let nav_bar: Element = - container(if self.condensed && state.selected_page.is_some() { - row![container(scrollable(column(pages) - .spacing(10) - .padding(10) - .max_width(200) - .width(Length::Units(200)) - .height(Length::Shrink))) - .height(Length::Fill) - .style(theme::Container::Custom(nav_bar_pages_style))] - } else if !state.section_active || self.condensed && state.selected_page.is_none() { - row![scrollable(column(sections) + let nav_bar: Element = container(if self.condensed { + row![ + scrollable(column(sections) .spacing(10) .padding(10) .max_width(100) .align_items(Alignment::Center) - .height(Length::Shrink))] - } else { - row![ - scrollable(column(sections) - .spacing(10) - .padding(10) - .max_width(100) - .align_items(Alignment::Center) - .height(Length::Shrink)), - container(scrollable(column(pages) - .spacing(10) - .padding(10) - .max_width(200) - .width(Length::Units(200)) - .height(Length::Shrink))) - .height(Length::Fill) - .style(theme::Container::Custom(nav_bar_pages_style)), - ] - }) - .height(Length::Fill) - .style(theme::Container::Custom(nav_bar_sections_style)) - .into(); + .height(Length::Shrink)), + container(scrollable(column(pages) + .spacing(10) + .padding(10) + .max_width(100) + .align_items(Alignment::Center) + .width(Length::Units(100)) + .height(Length::Shrink))) + .height(Length::Fill) + .style(theme::Container::Custom(nav_bar_pages_style)), + ] + } else { + row![ + scrollable(column(sections) + .spacing(10) + .padding(10) + .max_width(100) + .align_items(Alignment::Center) + .height(Length::Shrink)), + container(scrollable(column(pages) + .spacing(10) + .padding(10) + .max_width(200) + .width(Length::Units(200)) + .height(Length::Shrink))) + .height(Length::Fill) + .style(theme::Container::Custom(nav_bar_pages_style)), + ] + }) + .height(Length::Fill) + .style(theme::Container::Custom(nav_bar_sections_style)) + .into(); nav_bar } else { row![].into() @@ -183,4 +224,4 @@ pub fn section_button_style(theme: &Theme) -> Appearance { border_color: Default::default(), text_color: Default::default(), } -} +} \ No newline at end of file diff --git a/src/widget/view_switcher.rs b/src/widget/view_switcher.rs index 7cfe240e..0449bd1e 100644 --- a/src/widget/view_switcher.rs +++ b/src/widget/view_switcher.rs @@ -1,10 +1,10 @@ use derive_setters::Setters; use iced::{ alignment::{Horizontal, Vertical}, - theme, widget::{button, container, text, Row}, - Background, Element, Length, Renderer, Theme, Alignment, + Background, Length, Alignment, }; +use crate::{Element, Renderer, Theme, theme}; use iced_lazy::Component; #[derive(Setters)] @@ -40,8 +40,8 @@ impl<'a, Message> Component for ViewSwitcher<'a, Message> { 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![]; + fn view(&self, state: &Self::State) -> Element { + let mut options: Vec> = vec![]; for (index, option) in self.options.iter().enumerate() { options.push(