More efficently resize at break point
Uses iced `events_with()` to only subscribe to window resize events. The window width is stored in a static AtomicU32 so that the subscription can compare to an old window width as to only send messages when the width crosses the break point. fix up
This commit is contained in:
parent
bdf5f7da38
commit
8eff8a33fa
1 changed files with 148 additions and 132 deletions
|
|
@ -2,17 +2,17 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use cosmic::{
|
||||
iced_native,
|
||||
iced_native::window,
|
||||
iced::widget::{column, container, horizontal_space, row, text},
|
||||
iced::{self, Application, Command, Length},
|
||||
iced_lazy::responsive,
|
||||
iced::{self, Application, Command, Length, Subscription},
|
||||
iced_winit::window::{close, drag, toggle_maximize, minimize},
|
||||
theme::{self, Theme},
|
||||
widget::{icon, list, nav_bar, nav_button, header_bar, settings, scrollable, spin_button::{SpinButtonModel, SpinMessage}},
|
||||
Element,
|
||||
ElementExt,
|
||||
};
|
||||
use std::vec;
|
||||
use std::{vec, sync::atomic::{AtomicU32, Ordering}};
|
||||
|
||||
mod bluetooth;
|
||||
|
||||
|
|
@ -115,6 +115,9 @@ impl Default for Page {
|
|||
}
|
||||
}
|
||||
|
||||
static WINDOW_WIDTH: AtomicU32 = AtomicU32::new(0);
|
||||
const BREAK_POINT: u32 = 900;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Window {
|
||||
title: String,
|
||||
|
|
@ -168,7 +171,8 @@ pub enum Message {
|
|||
Minimize,
|
||||
Maximize,
|
||||
InputChanged,
|
||||
SpinButton(SpinMessage)
|
||||
SpinButton(SpinMessage),
|
||||
WindowWidthChanged(u32),
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
|
@ -179,6 +183,10 @@ impl Window {
|
|||
).into()
|
||||
}
|
||||
|
||||
fn is_condensed(&self) -> bool {
|
||||
WINDOW_WIDTH.load(Ordering::Relaxed) < BREAK_POINT
|
||||
}
|
||||
|
||||
fn parent_page_button(&self, sub_page: impl SubPage) -> Element<Message> {
|
||||
let page = sub_page.parent_page();
|
||||
column!(
|
||||
|
|
@ -258,6 +266,22 @@ impl Application for Window {
|
|||
self.title.clone()
|
||||
}
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
iced_native::subscription::events_with(|event, _| match event {
|
||||
cosmic::iced::Event::Window(_window_id, window::Event::Resized{width, height}) => {
|
||||
let old_width = WINDOW_WIDTH.load(Ordering::Relaxed);
|
||||
if old_width == 0
|
||||
|| old_width < BREAK_POINT && width > BREAK_POINT
|
||||
|| old_width > BREAK_POINT && width < BREAK_POINT {
|
||||
Some(width)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}).map(Message::WindowWidthChanged)
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> iced::Command<Self::Message> {
|
||||
match message {
|
||||
Message::Page(page) => {
|
||||
|
|
@ -282,6 +306,7 @@ impl Application for Window {
|
|||
Message::RowSelected(row) => println!("Selected row {row}"),
|
||||
Message::InputChanged => {},
|
||||
Message::SpinButton(msg) => self.spin_button.update(msg),
|
||||
Message::WindowWidthChanged(new_width) => WINDOW_WIDTH.store(new_width, Ordering::Relaxed),
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -289,148 +314,139 @@ impl Application for Window {
|
|||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
// TODO: Adding responsive makes this regenerate on every size change, and regeneration
|
||||
// involves allocations for many different items. Ideally, we could only make the nav bar
|
||||
// responsive and leave the content to be sized normally.
|
||||
responsive(|size| {
|
||||
//TODO: send a message when this happens instead of having everything be recalculated on resize
|
||||
let condensed = size.width < 900.0;
|
||||
let (sidebar_message, sidebar_toggled) = if self.is_condensed() {
|
||||
(Message::ToggleSidebarCondensed, self.sidebar_toggled_condensed)
|
||||
} else {
|
||||
(Message::ToggleSidebar, self.sidebar_toggled)
|
||||
};
|
||||
|
||||
let (sidebar_message, sidebar_toggled) = if condensed {
|
||||
(Message::ToggleSidebarCondensed, self.sidebar_toggled_condensed)
|
||||
} else {
|
||||
(Message::ToggleSidebar, self.sidebar_toggled)
|
||||
};
|
||||
let mut header = header_bar()
|
||||
.title("COSMIC Design System - Iced")
|
||||
.on_close(Message::Close)
|
||||
.on_drag(Message::Drag)
|
||||
.start(
|
||||
nav_button("Settings")
|
||||
.on_sidebar_toggled(sidebar_message)
|
||||
.sidebar_active(sidebar_toggled)
|
||||
.into()
|
||||
);
|
||||
|
||||
let mut header = header_bar()
|
||||
.title("COSMIC Design System - Iced")
|
||||
.on_close(Message::Close)
|
||||
.on_drag(Message::Drag)
|
||||
.start(
|
||||
nav_button("Settings")
|
||||
.on_sidebar_toggled(sidebar_message)
|
||||
.sidebar_active(sidebar_toggled)
|
||||
.into()
|
||||
);
|
||||
if self.show_maximize {
|
||||
header = header.on_maximize(Message::Maximize);
|
||||
}
|
||||
|
||||
if self.show_maximize {
|
||||
header = header.on_maximize(Message::Maximize);
|
||||
}
|
||||
if self.show_minimize {
|
||||
header = header.on_minimize(Message::Minimize);
|
||||
}
|
||||
|
||||
if self.show_minimize {
|
||||
header = header.on_minimize(Message::Minimize);
|
||||
}
|
||||
let header = Into::<Element<Message>>::into(header).debug(self.debug);
|
||||
|
||||
let header = Into::<Element<Message>>::into(header).debug(self.debug);
|
||||
let mut widgets = Vec::with_capacity(2);
|
||||
|
||||
let mut widgets = Vec::with_capacity(2);
|
||||
if sidebar_toggled {
|
||||
let sidebar_button_complex = |page: Page, active| {
|
||||
cosmic::nav_button!(
|
||||
page.icon_name(),
|
||||
page.title(),
|
||||
active
|
||||
)
|
||||
.on_press(Message::Page(page))
|
||||
};
|
||||
|
||||
if sidebar_toggled {
|
||||
let sidebar_button_complex = |page: Page, active| {
|
||||
cosmic::nav_button!(
|
||||
page.icon_name(),
|
||||
page.title(),
|
||||
active
|
||||
)
|
||||
.on_press(Message::Page(page))
|
||||
};
|
||||
let sidebar_button = |page: Page| {
|
||||
sidebar_button_complex(page, self.page == page)
|
||||
};
|
||||
|
||||
let sidebar_button = |page: Page| {
|
||||
sidebar_button_complex(page, self.page == page)
|
||||
};
|
||||
let mut sidebar = container(scrollable(column!(
|
||||
sidebar_button(Page::Demo),
|
||||
sidebar_button(Page::WiFi),
|
||||
sidebar_button_complex(Page::Networking(None), matches!(self.page, Page::Networking(_))),
|
||||
sidebar_button(Page::Bluetooth),
|
||||
sidebar_button_complex(Page::Desktop(None), matches!(self.page, Page::Desktop(_))),
|
||||
sidebar_button_complex(Page::InputDevices(None), matches!(self.page, Page::InputDevices(_))),
|
||||
sidebar_button(Page::Displays),
|
||||
sidebar_button(Page::PowerAndBattery),
|
||||
sidebar_button(Page::Sound),
|
||||
sidebar_button(Page::PrintersAndScanners),
|
||||
sidebar_button(Page::PrivacyAndSecurity),
|
||||
sidebar_button_complex(Page::SystemAndAccounts(None), matches!(self.page, Page::SystemAndAccounts(_))),
|
||||
sidebar_button(Page::UpdatesAndRecovery),
|
||||
sidebar_button_complex(Page::TimeAndLanguage(None), matches!(self.page, Page::TimeAndLanguage(_))),
|
||||
sidebar_button(Page::Accessibility),
|
||||
sidebar_button(Page::Applications),
|
||||
).spacing(14)))
|
||||
.height(Length::Fill)
|
||||
.padding(8)
|
||||
.style(theme::Container::Custom(nav_bar::nav_bar_sections_style));
|
||||
|
||||
let mut sidebar = container(scrollable(column!(
|
||||
sidebar_button(Page::Demo),
|
||||
sidebar_button(Page::WiFi),
|
||||
sidebar_button_complex(Page::Networking(None), matches!(self.page, Page::Networking(_))),
|
||||
sidebar_button(Page::Bluetooth),
|
||||
sidebar_button_complex(Page::Desktop(None), matches!(self.page, Page::Desktop(_))),
|
||||
sidebar_button_complex(Page::InputDevices(None), matches!(self.page, Page::InputDevices(_))),
|
||||
sidebar_button(Page::Displays),
|
||||
sidebar_button(Page::PowerAndBattery),
|
||||
sidebar_button(Page::Sound),
|
||||
sidebar_button(Page::PrintersAndScanners),
|
||||
sidebar_button(Page::PrivacyAndSecurity),
|
||||
sidebar_button_complex(Page::SystemAndAccounts(None), matches!(self.page, Page::SystemAndAccounts(_))),
|
||||
sidebar_button(Page::UpdatesAndRecovery),
|
||||
sidebar_button_complex(Page::TimeAndLanguage(None), matches!(self.page, Page::TimeAndLanguage(_))),
|
||||
sidebar_button(Page::Accessibility),
|
||||
sidebar_button(Page::Applications),
|
||||
).spacing(14)))
|
||||
.height(Length::Fill)
|
||||
.padding(8)
|
||||
.style(theme::Container::Custom(nav_bar::nav_bar_sections_style));
|
||||
if ! self.is_condensed() {
|
||||
sidebar = sidebar.max_width(300)
|
||||
}
|
||||
|
||||
if ! condensed {
|
||||
sidebar = sidebar.max_width(300)
|
||||
}
|
||||
let sidebar: Element<_> = sidebar.into();
|
||||
widgets.push(sidebar.debug(self.debug));
|
||||
}
|
||||
|
||||
let sidebar: Element<_> = sidebar.into();
|
||||
widgets.push(sidebar.debug(self.debug));
|
||||
}
|
||||
if ! (self.is_condensed() && sidebar_toggled) {
|
||||
let content: Element<_> = match self.page {
|
||||
Page::Demo => self.view_demo(),
|
||||
Page::Networking(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(NetworkingPage::Wired),
|
||||
self.sub_page_button(NetworkingPage::OnlineAccounts),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::Networking(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::Bluetooth => self.view_bluetooth(),
|
||||
Page::Desktop(desktop_page_opt) => self.view_desktop(desktop_page_opt),
|
||||
Page::InputDevices(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(InputDevicesPage::Keyboard),
|
||||
self.sub_page_button(InputDevicesPage::Touchpad),
|
||||
self.sub_page_button(InputDevicesPage::Mouse),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::InputDevices(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::SystemAndAccounts(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(SystemAndAccountsPage::Users),
|
||||
self.sub_page_button(SystemAndAccountsPage::About),
|
||||
self.sub_page_button(SystemAndAccountsPage::Firmware),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::SystemAndAccounts(Some(SystemAndAccountsPage::About)) => self.view_system_and_accounts_about(),
|
||||
Page::SystemAndAccounts(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::TimeAndLanguage(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(TimeAndLanguagePage::DateAndTime),
|
||||
self.sub_page_button(TimeAndLanguagePage::RegionAndLanguage),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::TimeAndLanguage(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
_ => self.view_unimplemented_page(self.page),
|
||||
};
|
||||
|
||||
if ! (condensed && sidebar_toggled) {
|
||||
let content: Element<_> = match self.page {
|
||||
Page::Demo => self.view_demo(),
|
||||
Page::Networking(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(NetworkingPage::Wired),
|
||||
self.sub_page_button(NetworkingPage::OnlineAccounts),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::Networking(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::Bluetooth => self.view_bluetooth(),
|
||||
Page::Desktop(desktop_page_opt) => self.view_desktop(desktop_page_opt),
|
||||
Page::InputDevices(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(InputDevicesPage::Keyboard),
|
||||
self.sub_page_button(InputDevicesPage::Touchpad),
|
||||
self.sub_page_button(InputDevicesPage::Mouse),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::InputDevices(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::SystemAndAccounts(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(SystemAndAccountsPage::Users),
|
||||
self.sub_page_button(SystemAndAccountsPage::About),
|
||||
self.sub_page_button(SystemAndAccountsPage::Firmware),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::SystemAndAccounts(Some(SystemAndAccountsPage::About)) => self.view_system_and_accounts_about(),
|
||||
Page::SystemAndAccounts(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
Page::TimeAndLanguage(None) => settings::view_column(vec![
|
||||
self.page_title(self.page),
|
||||
column!(
|
||||
self.sub_page_button(TimeAndLanguagePage::DateAndTime),
|
||||
self.sub_page_button(TimeAndLanguagePage::RegionAndLanguage),
|
||||
).spacing(16).into()
|
||||
]).into(),
|
||||
Page::TimeAndLanguage(Some(sub_page)) => self.view_unimplemented_sub_page(sub_page),
|
||||
_ => self.view_unimplemented_page(self.page),
|
||||
};
|
||||
widgets.push(
|
||||
scrollable(row![
|
||||
horizontal_space(Length::Fill),
|
||||
content.debug(self.debug),
|
||||
horizontal_space(Length::Fill),
|
||||
])
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
widgets.push(
|
||||
scrollable(row![
|
||||
horizontal_space(Length::Fill),
|
||||
content.debug(self.debug),
|
||||
horizontal_space(Length::Fill),
|
||||
])
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
let content = container(row(widgets))
|
||||
.padding([0, 8, 8, 8])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into();
|
||||
|
||||
let content = container(row(widgets))
|
||||
.padding([0, 8, 8, 8])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into();
|
||||
|
||||
column(vec![header, content]).into()
|
||||
})
|
||||
.into()
|
||||
column(vec![header, content]).into()
|
||||
}
|
||||
|
||||
fn theme(&self) -> Theme {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue