From ff2f3e574c0df0489d1c83604530c386029f6393 Mon Sep 17 00:00:00 2001 From: Eduardo Flores Date: Thu, 13 Oct 2022 16:01:21 -0700 Subject: [PATCH] Better responsiveness for the Navigation Bar --- .gitignore | 3 +- examples/cosmic/src/window.rs | 82 +++++++------------- src/widget/navigation/navbar.rs | 128 +++++++++++++++----------------- 3 files changed, 91 insertions(+), 122 deletions(-) diff --git a/.gitignore b/.gitignore index 6a59f558..8f97d0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Cargo.lock -/.idea \ No newline at end of file +/.idea +/.fleet \ No newline at end of file diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index c3b42475..e12be48b 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -19,7 +19,8 @@ use theme::Button as ButtonTheme; #[derive(Default)] pub struct Window { title: String, - page: u8, + page: usize, + section: usize, debug: bool, theme: Theme, slider_value: f32, @@ -52,7 +53,7 @@ impl Window { #[allow(dead_code)] #[derive(Clone, Copy, Debug)] pub enum Message { - Page(u8), + Page(usize, usize), Debug(bool), ThemeChanged(Theme), ButtonPressed, @@ -92,7 +93,10 @@ impl Application for Window { fn update(&mut self, message: Message) -> iced::Command { match message { - Message::Page(page) => self.page = page, + Message::Page(section, page) => { + self.page = page; + self.section = section; + } Message::Debug(debug) => self.debug = debug, Message::ThemeChanged(theme) => self.theme = theme, Message::ButtonPressed => {} @@ -138,79 +142,49 @@ impl Application for Window { // responsive and leave the content to be sized normally. let content = responsive(|size| { let condensed = size.width < 900.0; - - // cosmic::navbar![ - // nav_text_button("network-wireless", "Network & Wireless", condensed) - // .on_press(Message::Page(0)) - // .style(if self.page == 0 { - // ButtonTheme::Primary - // } else { - // ButtonTheme::Text - // }), - // nav_text_button("preferences-desktop", "Bluetooth", condensed) - // .on_press(Message::Page(1)) - // .style(if self.page == 1 { - // ButtonTheme::Primary - // } else { - // ButtonTheme::Text - // }), - // nav_text_button("system-software-update", "Personalization", condensed) - // .on_press(Message::Page(2)) - // .style(if self.page == 2 { - // ButtonTheme::Primary - // } else { - // ButtonTheme::Text - // }), - // ] - let sidebar: Element<_> = nav_bar() .source(BTreeMap::from([ ( - nav_bar_section() + nav_bar_item() .title("Network & Wireless") - .icon("network-wireless"), - vec![nav_bar_page("Wi-Fi")], + .icon("nm-device-wired"), + vec![nav_bar_item().title("Wi-Fi").icon("network-wireless")], ), ( - nav_bar_section() - .title("Bluetooth") - .icon("cs-bluetooth"), - vec![nav_bar_page("Devices")], + nav_bar_item().title("Bluetooth").icon("cs-bluetooth"), + vec![nav_bar_item().title("Devices").icon("computer")], ), ( - nav_bar_section() + nav_bar_item() .title("Personalization") .icon("applications-system"), vec![ - nav_bar_page("Desktop Session"), - nav_bar_page("Wallpaper"), - nav_bar_page("Appearance"), - nav_bar_page("Dock & Top Panel"), - nav_bar_page("Workspaces"), - nav_bar_page("Notifications"), + 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_section() - .title("Input Devices") - .icon("input-keyboard"), - vec![nav_bar_page("Keyboard")], + nav_bar_item().title("Input Devices").icon("input-keyboard"), + vec![nav_bar_item().title("Keyboard").icon("computer")], ), ( - nav_bar_section().title("Displays").icon("cs-display"), - vec![nav_bar_page("Keyboard")], + nav_bar_item().title("Displays").icon("cs-display"), + vec![nav_bar_item().title("External Monitors").icon("computer")], ), ( - nav_bar_section() - .title("Power & Battery") - .icon("battery"), - vec![nav_bar_page("Status")], + nav_bar_item().title("Power & Battery").icon("battery"), + vec![nav_bar_item().title("Status").icon("computer")], ), ( - nav_bar_section().title("Sound").icon("sound"), - vec![nav_bar_page("Volume")], + 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(); diff --git a/src/widget/navigation/navbar.rs b/src/widget/navigation/navbar.rs index a3d006fc..a81fb4fb 100644 --- a/src/widget/navigation/navbar.rs +++ b/src/widget/navigation/navbar.rs @@ -14,10 +14,11 @@ use std::collections::BTreeMap; #[derive(Setters, Default)] pub struct NavBar<'a, Message> { - source: BTreeMap>, + source: BTreeMap>, active: bool, condensed: bool, - on_page_selected: Option Message + 'a>>, + #[setters(strip_option)] + on_page_selected: Option Message + 'a>>, } impl<'a, Message> NavBar<'a, Message> { @@ -36,55 +37,34 @@ pub fn nav_bar<'a, Message>() -> NavBar<'a, Message> { } #[derive(Setters, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct NavBarSection { +pub struct NavBarItem { #[setters(into)] title: String, #[setters(into)] icon: String, } -impl NavBarSection { +impl NavBarItem { pub fn new() -> Self { Self::default() } } -pub fn nav_bar_section() -> NavBarSection { - NavBarSection::new() -} - -#[derive(Default, Clone, Setters, PartialOrd, Ord, PartialEq, Eq)] -pub struct NavBarPage { - #[setters(into)] - title: String, -} - -impl NavBarPage { - pub fn new() -> Self { - Self { - title: String::new(), - } - } -} - -pub fn nav_bar_page(title: &str) -> NavBarPage { - let mut page = NavBarPage::new(); - page.title = title.to_string(); - page +pub fn nav_bar_item() -> NavBarItem { + NavBarItem::new() } #[derive(Clone)] pub enum NavBarEvent { - SectionSelected(NavBarSection), - PageSelected(NavBarSection, NavBarPage), + SectionSelected(usize), + PageSelected(usize, usize), + RevealSections, } #[derive(Default)] pub struct NavBarState { - selected_section: NavBarSection, - section_active: bool, - selected_page: Option, - page_active: bool, + selected_section: usize, + selected_page: Option, } impl<'a, Message> Component for NavBar<'a, Message> { @@ -94,27 +74,20 @@ impl<'a, Message> Component for NavBar<'a, Message> { fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option { match event { NavBarEvent::SectionSelected(section) => { - if state.selected_section == section { - state.section_active = !state.section_active; - } else { - state.selected_section = section; - state.section_active = true; - } + state.selected_section = section; state.selected_page = None; - state.page_active = false; None } NavBarEvent::PageSelected(section, page) => { - if state.selected_page.is_some() && &page == state.selected_page.as_ref().unwrap() { - state.page_active = !state.page_active; - } else { - state.selected_page = Some(page.clone()); - state.page_active = true; - } + state.selected_page = Some(page); self.on_page_selected .as_ref() .map(|on_page_selected| (on_page_selected)(section, page)) } + NavBarEvent::RevealSections => { + state.selected_page = None; + None + } } } @@ -123,7 +96,7 @@ impl<'a, Message> Component for NavBar<'a, Message> { let mut sections: Vec> = vec![]; let mut pages: Vec> = vec![]; - for (section, section_pages) in &self.source { + for (section_index, (section, section_pages)) in self.source.iter().enumerate() { sections.push( button( column(vec![ @@ -134,33 +107,54 @@ impl<'a, Message> Component for NavBar<'a, Message> { .height(Length::Units(50)) .align_items(Alignment::Center), ) - .style(if *section == state.selected_section && state.section_active { + .style(if section_index == state.selected_section { theme::Button::Primary.into() } else { theme::Button::Text.into() }) - .on_press(NavBarEvent::SectionSelected(section.clone())) + .on_press(NavBarEvent::SectionSelected(section_index)) .into(), ); - if *section == state.selected_section { - for page in section_pages { - pages.push( - button(row![text(&page.title).size(16).width(Length::Fill)]) - .padding(10) - .style( - if let Some(selected_page) = &state.selected_page { - if state.page_active && page == selected_page { - theme::Button::Primary.into() - } else { - theme::Button::Text.into() - } - } else { - theme::Button::Text.into() - } - ) - .on_press(NavBarEvent::PageSelected(section.clone(), page.clone())) - .into(), - ); + if section_index == state.selected_section { + for (page_index, page) in section_pages.iter().enumerate() { + 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() + }); } } }