refactor: libcosmic rebase with Application API

This commit is contained in:
Michael Aaron Murphy 2023-09-19 16:54:50 +02:00 committed by Michael Murphy
parent d243e45094
commit 454894d82f
18 changed files with 1081 additions and 1198 deletions

1128
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,6 @@ git = "https://github.com/pop-os/libcosmic"
[workspace.dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic"
default-features = false
features = ["debug", "wayland", "tokio"]
[workspace.dependencies.cosmic-config]
@ -24,10 +23,10 @@ git = "https://github.com/pop-os/cosmic-comp"
git = "https://github.com/pop-os/cosmic-panel"
[patch."https://github.com/pop-os/libcosmic"]
# libcosmic = { path = "../libcosmic" }
# cosmic-config = { path = "../libcosmic/cosmic-config" }
# libcosmic = { git = "https://github.com/pop-os/libcosmic?rev=master", branch = "flexalloc" }
# cosmic-config = { git = "https://github.com/pop-os/libcosmic?rev=master", branch = "flexalloc" }
# libcosmic = { path = "../../libcosmic" }
# cosmic-config = { path = "../../libcosmic/cosmic-config" }
# libcosmic = { git = "https://github.com/pop-os/libcosmic?rev=master", branch = "improv" }
# cosmic-config = { git = "https://github.com/pop-os/libcosmic?rev=master", branch = "improv" }
[profile.release]
opt-level = 3

View file

@ -1,159 +1,96 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
use apply::Apply;
use cosmic::iced::Subscription;
use cosmic::{
app::{Command, Core},
cosmic_config::config_subscription,
iced::{self, event::wayland, event::PlatformSpecific, subscription, window, Length},
prelude::*,
widget::{
column, container, icon, nav_bar, navigation, scrollable, search, segmented_button,
settings,
},
Element,
};
use cosmic_panel_config::CosmicPanelConfig;
use cosmic_settings_page::{self as page, section};
use cosmic::{
cosmic_config::config_subscription,
iced::{
use crate::config::Config;
use crate::pages::desktop::{
self,
dock::{self, applets::ADD_DOCK_APPLET_DIALOGUE_ID},
panel::{
self,
event::wayland::{self, WindowEvent, WindowState},
event::PlatformSpecific,
subscription, window, Application, Color, Command, Length, Subscription,
applets_inner::{self, AppletsPage, APPLET_DND_ICON_ID},
inner as _panel,
},
iced::{
widget::{self, column, container, horizontal_space, row},
window::Mode,
},
iced_sctk::commands::window::{set_mode_window, start_drag_window},
iced_style::application,
keyboard_nav,
theme::{self, theme_subscription, Theme},
widget::{
header_bar, nav_bar, nav_bar_toggle, scrollable, search, segmented_button, settings,
IconSource,
},
Element, ElementExt,
};
use page::Page;
use crate::{
config::Config,
pages::{
desktop::{
self,
dock::{self, applets::ADD_DOCK_APPLET_DIALOGUE_ID},
panel::{
self,
applets_inner::{self, AppletsPage, APPLET_DND_ICON_ID},
inner as _panel,
},
},
input::{self, keyboard},
sound, system, time,
},
subscription::desktop_files,
widget::{page_title, parent_page_button, search_header, sub_page_button},
};
use std::{borrow::Cow, process};
use crate::pages::input::{self, keyboard};
use crate::pages::{sound, system, time};
use crate::subscription::desktop_files;
use crate::widget::{page_title, search_header};
use std::borrow::Cow;
#[allow(clippy::struct_excessive_bools)]
#[allow(clippy::module_name_repetitions)]
pub struct SettingsApp {
pub active_page: page::Entity,
pub config: Config,
pub debug: bool,
pub nav_bar_toggled_condensed: bool,
pub nav_bar_toggled: bool,
pub nav_bar: segmented_button::SingleSelectModel,
pub pages: page::Binder<crate::pages::Message>,
pub scaling_factor: f32,
pub search: search::Model,
pub search_selections: Vec<(page::Entity, section::Entity)>,
pub show_maximize: bool,
pub sharp_corners: bool,
pub show_minimize: bool,
pub theme: Theme,
pub title: String,
pub window_width: u32,
active_page: page::Entity,
config: Config,
core: Core,
nav_model: nav_bar::Model,
pages: page::Binder<crate::pages::Message>,
search: search::Model,
search_selections: Vec<(page::Entity, section::Entity)>,
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub enum Message {
Close,
Drag,
KeyboardNav(keyboard_nav::Message),
Maximize,
Minimize,
NavBar(segmented_button::Entity),
None,
DesktopInfo,
Page(page::Entity),
PageMessage(crate::pages::Message),
Search(search::Message),
ToggleNavBar,
ToggleNavBarCondensed,
WindowResize(u32, u32),
WindowState(WindowState),
PanelConfig(CosmicPanelConfig),
DesktopInfo,
ThemeChanged(Theme),
Search(search::Message),
SetWindowTitle,
}
impl Application for SettingsApp {
impl cosmic::Application for SettingsApp {
type Executor = cosmic::executor::single::Executor;
type Flags = ();
type Message = Message;
type Theme = Theme;
fn new(_: Self::Flags) -> (Self, Command<Self::Message>) {
const APP_ID: &'static str = "com.system76.CosmicSettings";
fn core(&self) -> &Core {
&self.core
}
fn core_mut(&mut self) -> &mut Core {
&mut self.core
}
fn init(core: Core, _flags: Self::Flags) -> (Self, Command<Self::Message>) {
let mut app = SettingsApp {
sharp_corners: false,
active_page: page::Entity::default(),
config: Config::new(),
debug: false,
nav_bar: segmented_button::Model::default(),
nav_bar_toggled: true,
nav_bar_toggled_condensed: false,
core,
nav_model: nav_bar::Model::default(),
pages: page::Binder::default(),
title: crate::fl!("app"),
scaling_factor: std::env::var("COSMIC_SCALE")
.ok()
.and_then(|scale| scale.parse::<f32>().ok())
.unwrap_or(1.0),
search: search::Model::default(),
search_selections: Vec::default(),
show_maximize: true,
show_minimize: true,
window_width: 0,
theme: cosmic::theme::theme(),
};
// app.insert_page::<wifi::Page>();
// app.insert_page::<networking::Page>();
// app.insert_page::<bluetooth::Page>();
let desktop_id = app.insert_page::<desktop::Page>().id();
// app.insert_page::<panel::Page>();
// app.insert_page::<dock::Page>();
// app.insert_page::<input::Page>();
// app.insert_page::<displays::Page>();
// app.insert_page::<power::Page>();
app.insert_page::<sound::Page>();
// app.insert_page::<printers::Page>();
// app.insert_page::<privacy::Page>();
app.insert_page::<system::Page>();
app.insert_page::<time::Page>();
// app.insert_page::<accessibility::Page>();
// app.insert_page::<applications::Page>();
//
app.insert_page::<input::Page>();
let active_id = app
.pages
.info
.iter()
.find(|(_id, info)| info.id == *app.config.active_page)
.find_page_by_id(&app.config.active_page)
.map_or(desktop_id, |(id, _info)| id);
let command = app.activate_page(active_id);
@ -161,19 +98,49 @@ impl Application for SettingsApp {
(app, command)
}
fn title(&self) -> String {
self.title.clone()
fn nav_model(&self) -> Option<&nav_bar::Model> {
Some(&self.nav_model)
}
fn on_close_requested(&self, id: window::Id) -> Option<Self::Message> {
let message = if id == applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID {
Message::PageMessage(crate::pages::Message::PanelApplet(
applets_inner::Message::ClosedAppletDialogue,
))
} else if id == ADD_DOCK_APPLET_DIALOGUE_ID {
Message::PageMessage(crate::pages::Message::DockApplet(dock::applets::Message(
applets_inner::Message::ClosedAppletDialogue,
)))
} else {
return None;
};
Some(message)
}
fn on_escape(&mut self) -> Command<Self::Message> {
if self.search.is_active() {
self.search.state = search::State::Inactive;
self.search_clear();
}
Command::none()
}
fn on_nav_select(&mut self, id: nav_bar::Id) -> Command<Self::Message> {
if let Some(page) = self.nav_model.data::<page::Entity>(id).copied() {
return self.activate_page(page);
}
Command::none()
}
fn on_search(&mut self) -> Command<Self::Message> {
self.search.focus()
}
fn subscription(&self) -> Subscription<Message> {
let window_break = subscription::events_with(|event, _| match event {
iced::Event::Window(_window_id, window::Event::Resized { width, height }) => {
Some(Message::WindowResize(width, height))
}
iced::Event::PlatformSpecific(PlatformSpecific::Wayland(wayland::Event::Window(
WindowEvent::State(s),
..,
))) => Some(Message::WindowState(s)),
iced::Event::PlatformSpecific(PlatformSpecific::Wayland(wayland::Event::Output(
wayland::OutputEvent::Created(Some(info)),
o,
@ -191,7 +158,6 @@ impl Application for SettingsApp {
Subscription::batch(vec![
window_break,
keyboard_nav::subscription().map(Message::KeyboardNav),
desktop_files(0).map(|_| Message::DesktopInfo),
config_subscription(0, "com.system76.CosmicPanel.Panel".into(), 1).map(
|(_, e)| match e {
@ -215,64 +181,28 @@ impl Application for SettingsApp {
}
},
),
theme_subscription(0).map(Message::ThemeChanged),
])
}
#[allow(clippy::too_many_lines)]
fn update(&mut self, message: Message) -> iced::Command<Self::Message> {
let mut ret = Command::none();
fn update(&mut self, message: Message) -> Command<Self::Message> {
match message {
Message::WindowResize(_width, _height) => {}
Message::KeyboardNav(message) => match message {
keyboard_nav::Message::Unfocus => ret = keyboard_nav::unfocus(),
keyboard_nav::Message::FocusNext => ret = widget::focus_next(),
keyboard_nav::Message::FocusPrevious => ret = widget::focus_previous(),
keyboard_nav::Message::Escape => {
if self.search.is_active() {
self.search.state = search::State::Inactive;
self.search_clear();
}
}
keyboard_nav::Message::Search => {
return self.search.focus();
}
},
Message::Page(page) => {
return self.activate_page(page);
}
Message::Drag => return start_drag_window(window::Id(0)),
Message::Close => {
process::exit(0);
}
Message::Minimize => return set_mode_window(window::Id(0), Mode::Hidden),
Message::Maximize => {
if self.sharp_corners {
self.sharp_corners = false;
return set_mode_window(window::Id(0), Mode::Windowed);
}
Message::Page(page) => return self.activate_page(page),
Message::SetWindowTitle => return self.set_window_title(),
self.sharp_corners = true;
return set_mode_window(window::Id(0), Mode::Fullscreen);
}
Message::NavBar(key) => {
if let Some(page) = self.nav_bar.data::<page::Entity>(key).copied() {
return self.activate_page(page);
}
}
Message::ToggleNavBar => self.nav_bar_toggled = !self.nav_bar_toggled,
Message::ToggleNavBarCondensed => {
self.nav_bar_toggled_condensed = !self.nav_bar_toggled_condensed;
}
Message::Search(search::Message::Activate) => {
return self.search.focus();
}
Message::Search(search::Message::Changed(phrase)) => {
self.search_changed(phrase);
}
Message::Search(search::Message::Clear) => {
self.search_clear();
}
Message::PageMessage(message) => match message {
crate::pages::Message::About(message) => {
page::update!(self.pages, message, system::about::Page);
@ -288,7 +218,7 @@ impl Application for SettingsApp {
}
crate::pages::Message::Input(message) => {
if let Some(page) = self.pages.page_mut::<input::Page>() {
return page.update(message);
return page.update(message).map(cosmic::app::Message::App);
}
}
crate::pages::Message::External { .. } => {
@ -302,7 +232,9 @@ impl Application for SettingsApp {
}
crate::pages::Message::PanelApplet(message) => {
if let Some(page) = self.pages.page_mut::<applets_inner::Page>() {
return page.update(message, applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID);
return page
.update(message, applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID)
.map(cosmic::app::Message::App);
}
}
crate::pages::Message::Dock(message) => {
@ -310,13 +242,11 @@ impl Application for SettingsApp {
}
crate::pages::Message::DockApplet(message) => {
if let Some(page) = self.pages.page_mut::<dock::applets::Page>() {
return page.update(message);
return page.update(message).map(cosmic::app::Message::App);
}
}
},
Message::WindowState(state) => {
self.sharp_corners = matches!(state, WindowState::Activated);
}
Message::PanelConfig(config) if config.name.to_lowercase().contains("panel") => {
page::update!(
self.pages,
@ -325,12 +255,15 @@ impl Application for SettingsApp {
);
if let Some(page) = self.pages.page_mut::<applets_inner::Page>() {
return page.update(
applets_inner::Message::PanelConfig(config),
applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID,
);
return page
.update(
applets_inner::Message::PanelConfig(config),
applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID,
)
.map(cosmic::app::Message::App);
}
}
Message::PanelConfig(config) if config.name.to_lowercase().contains("dock") => {
page::update!(
self.pages,
@ -343,6 +276,7 @@ impl Application for SettingsApp {
dock::applets::Page
);
}
Message::DesktopInfo => {
let info_list: Vec<_> = freedesktop_desktop_entry::Iter::new(
freedesktop_desktop_entry::default_paths(),
@ -356,22 +290,45 @@ impl Application for SettingsApp {
dock::applets::Page
);
if let Some(page) = self.pages.page_mut::<applets_inner::Page>() {
return page.update(
applets_inner::Message::Applets(info_list),
applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID,
);
return page
.update(
applets_inner::Message::Applets(info_list),
applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID,
)
.map(cosmic::app::Message::App);
}
}
Message::ThemeChanged(theme) => {
self.theme = theme;
}
Message::PanelConfig(_) | Message::None | Message::Search(_) => {} // Ignored
Message::PanelConfig(_) | Message::Search(_) => {} // Ignored
}
ret
Command::none()
}
fn view(&self) -> Element<Message> {
let page_view = if self.search.is_active() {
self.search_view()
} else if let Some(content) = self.pages.content(self.active_page) {
self.page_view(content)
} else if let Some(sub_pages) = self.pages.sub_pages(self.active_page) {
self.sub_page_view(sub_pages)
} else {
panic!("page without sub-pages or content");
};
container(page_view)
.max_width(800)
.width(Length::Fill)
.apply(container)
.center_x()
.padding([0, 64])
.width(Length::Fill)
.apply(scrollable)
.into()
}
#[allow(clippy::too_many_lines)]
fn view(&self, id: window::Id) -> Element<Message> {
fn view_window(&self, id: window::Id) -> Element<Message> {
if let Some(Some(page)) =
(id == APPLET_DND_ICON_ID).then(|| self.pages.page::<applets_inner::Page>())
{
@ -400,129 +357,13 @@ impl Application for SettingsApp {
return page.special_character_key_view();
}
cosmic::iced::widget::responsive(|size| {
let is_condensed = (600.0 * self.scaling_factor) > size.width;
let narrow_navbar = (700.0 * self.scaling_factor) > size.width;
let (nav_bar_message, nav_bar_toggled) = if is_condensed {
(
Message::ToggleNavBarCondensed,
self.nav_bar_toggled_condensed,
)
} else {
(Message::ToggleNavBar, self.nav_bar_toggled)
};
let mut header = header_bar()
.title("")
.on_close(Message::Close)
.on_drag(Message::Drag)
.start(
iced::widget::row!(
nav_bar_toggle()
.on_nav_bar_toggled(nav_bar_message)
.nav_bar_active(nav_bar_toggled),
search::search(&self.search, Message::Search)
)
.align_items(iced::Alignment::Center)
.into(),
);
if self.show_maximize {
header = header.on_maximize(Message::Maximize);
}
if self.show_minimize {
header = header.on_minimize(Message::Minimize);
}
let header = Into::<Element<Message>>::into(header).debug(self.debug);
let mut widgets = Vec::with_capacity(2);
if nav_bar_toggled {
let mut nav_bar = nav_bar(&self.nav_bar, Message::NavBar);
if !is_condensed {
nav_bar = nav_bar.max_width(if narrow_navbar { 200 } else { 300 });
}
let nav_bar: Element<_> = nav_bar.into();
widgets.push(nav_bar.debug(self.debug));
}
if !(is_condensed && nav_bar_toggled) {
widgets.push(
scrollable(row![
horizontal_space(Length::Fill),
(if self.search.is_active() {
self.search_view()
} else if let Some(content) = self.pages.content(self.active_page) {
self.page_view(content)
} else if let Some(sub_pages) = self.pages.sub_pages(self.active_page) {
self.sub_page_view(sub_pages)
} else {
panic!("page without sub-pages or content");
})
.debug(self.debug),
horizontal_space(Length::Fill),
])
.into(),
);
}
let content = container(row(widgets).spacing(8))
.padding([0, 8, 8, 8])
.width(Length::Fill)
.height(Length::Fill)
.style(theme::Container::Background)
.into();
column(vec![header, content]).into()
})
.into()
}
fn theme(&self) -> Theme {
self.theme.clone()
}
fn scale_factor(&self) -> f64 {
self.scaling_factor as f64
}
fn close_requested(&self, id: window::Id) -> Self::Message {
if id == window::Id(0) {
Message::Close
} else if id == applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID {
Message::PageMessage(crate::pages::Message::PanelApplet(
applets_inner::Message::ClosedAppletDialogue,
))
} else if id == ADD_DOCK_APPLET_DIALOGUE_ID {
Message::PageMessage(crate::pages::Message::DockApplet(dock::applets::Message(
applets_inner::Message::ClosedAppletDialogue,
)))
} else {
Message::None
}
}
fn style(&self) -> <Self::Theme as cosmic::iced_style::application::StyleSheet>::Style {
if self.sharp_corners {
cosmic::theme::Application::default()
} else {
cosmic::theme::Application::Custom(Box::new(|theme| application::Appearance {
background_color: Color::TRANSPARENT,
text_color: theme.cosmic().on_bg_color().into(),
}))
}
panic!("unknown window ID: {id:?}");
}
}
impl SettingsApp {
/// Activates a page.
fn activate_page(&mut self, page: page::Entity) -> Command<crate::Message> {
self.nav_bar_toggled_condensed = false;
let current_page = self.active_page;
self.active_page = page;
@ -536,10 +377,25 @@ impl SettingsApp {
self.search.state = search::State::Inactive;
self.activate_navbar(page);
self.pages
let page_command = self
.pages
.page_reload(page)
.unwrap_or(Command::none())
.unwrap_or(iced::Command::none())
.map(Message::PageMessage)
.map(cosmic::app::Message::App);
Command::batch(vec![
page_command,
cosmic::command::future(async { Message::SetWindowTitle })
.map(cosmic::app::Message::App),
])
}
fn set_window_title(&self) -> Command<crate::Message> {
cosmic::app::command::set_title(format!(
"{} - COSMIC Settings",
self.pages.info[self.active_page].title
))
}
/// Activates the navbar item associated with a page.
@ -549,7 +405,7 @@ impl SettingsApp {
}
if let Some(nav_id) = self.pages.data(page) {
self.nav_bar.activate(*nav_id);
self.nav_model.activate(*nav_id);
}
}
@ -569,10 +425,10 @@ impl SettingsApp {
fn navbar_insert(&mut self, id: page::Entity) -> segmented_button::SingleSelectEntityMut {
let page = &self.pages.info[id];
self.nav_bar
self.nav_model
.insert()
.text(page.title.clone())
.icon(IconSource::from(page.icon_name.clone()))
.icon(icon::from_name(&*page.icon_name).into())
.data(id)
.with_id(|nav_id| self.pages.data_set(id, nav_id))
}
@ -583,9 +439,9 @@ impl SettingsApp {
let mut column_widgets = Vec::with_capacity(1);
if let Some(parent) = page.parent {
column_widgets.push(parent_page_button(
&self.pages.info[parent],
page,
column_widgets.push(navigation::sub_page_header(
page.title.as_str(),
self.pages.info[parent].title.as_str(),
Message::Page(parent),
));
}
@ -600,10 +456,7 @@ impl SettingsApp {
);
}
settings::view_column(column_widgets)
.max_width(683)
.padding(0)
.into()
settings::view_column(column_widgets).padding(0).into()
}
fn search_changed(&mut self, phrase: String) {
@ -667,18 +520,22 @@ impl SettingsApp {
/// Displays the sub-pages view of a page.
fn sub_page_view(&self, sub_pages: &[page::Entity]) -> cosmic::Element<Message> {
let page = &self.pages.info[self.active_page];
let mut column_widgets = Vec::with_capacity(sub_pages.len());
column_widgets.push(page_title(page));
let mut page_list = column::with_capacity(sub_pages.len()).spacing(18);
for entity in sub_pages.iter().copied() {
let sub_page = &self.pages.info[entity];
column_widgets.push(sub_page_button(entity, sub_page));
page_list = page_list.push(navigation::page_list_item(
sub_page.title.as_str(),
sub_page.description.as_str(),
&sub_page.icon_name,
entity,
));
}
settings::view_column(column_widgets)
.apply(Element::from)
.map(Message::Page)
column::with_capacity(2)
.push(page_title(&self.pages.info[self.active_page]))
.push(Element::from(page_list).map(Message::Page))
.spacing(24)
.into()
}
}

View file

@ -19,7 +19,7 @@ pub mod widget;
pub mod subscription;
use cosmic::{
iced::{wayland::actions::window::SctkWindowSettings, Application, Limits},
iced::{wayland::actions::window::SctkWindowSettings, Limits},
iced_sctk::settings::InitialSurface,
};
use i18n_embed::DesktopLanguageRequester;
@ -38,17 +38,10 @@ pub fn main() -> color_eyre::Result<()> {
init_logger();
init_localizer();
cosmic::settings::set_default_icon_theme("Pop");
let mut settings = cosmic::settings();
settings.default_text_size = 14.0;
settings.initial_surface = InitialSurface::XdgWindow(SctkWindowSettings {
title: Some(fl!("app")),
size_limits: Limits::NONE.min_width(400.0).min_height(300.0),
app_id: Some("com.system76.CosmicSettings".to_string()),
..Default::default()
});
let settings = cosmic::app::Settings::default()
.size_limits(Limits::NONE.min_width(400.0).min_height(300.0));
SettingsApp::run(settings)?;
cosmic::app::run::<app::SettingsApp>(settings, ())?;
Ok(())
}

View file

@ -4,10 +4,9 @@
use super::Message;
use apply::Apply;
use cosmic::{
iced::widget::{button, container, horizontal_space, row},
iced::Length,
theme,
widget::{icon, list, settings, toggler},
widget::{button, container, horizontal_space, icon, list, row, settings, toggler},
Element,
};
@ -117,18 +116,19 @@ pub fn panel_dock_links() -> Section<crate::pages::Message> {
settings = if let Some((panel_entity, panel_info)) =
binder.info.iter().find(|(_, v)| v.id == "panel")
{
let control = row::with_children(vec![
horizontal_space(Length::Fill).into(),
icon::from_name("go-next-symbolic").size(16).into(),
]);
settings.add(
settings::item::builder(panel_info.title.clone())
.description(panel_info.description.clone())
.control(row!(
horizontal_space(Length::Fill),
icon("go-next-symbolic", 20).style(theme::Svg::Symbolic)
))
.control(control)
.spacing(16)
.apply(container)
.style(theme::Container::custom(list::column::style))
.style(theme::Container::custom(list::style))
.apply(button)
.padding(0)
.style(theme::Button::Transparent)
.on_press(crate::pages::Message::Page(panel_entity)),
)
@ -139,18 +139,19 @@ pub fn panel_dock_links() -> Section<crate::pages::Message> {
settings = if let Some((dock_entity, dock_info)) =
binder.info.iter().find(|(_, v)| v.id == "dock")
{
let control = row::with_children(vec![
horizontal_space(Length::Fill).into(),
icon::from_name("go-next-symbolic").size(16).into(),
]);
settings.add(
settings::item::builder(dock_info.title.clone())
.description(dock_info.description.clone())
.control(row!(
horizontal_space(Length::Fill),
icon("go-next-symbolic", 20).style(theme::Svg::Symbolic)
))
.control(control)
.spacing(16)
.apply(container)
.style(theme::Container::custom(list::column::style))
.style(theme::Container::custom(list::style))
.apply(button)
.padding(0)
.style(theme::Button::Transparent)
.on_press(crate::pages::Message::Page(dock_entity)),
)

View file

@ -1,4 +1,11 @@
use apply::Apply;
use button::StyleSheet as ButtonStyleSheet;
use cosmic::iced_style::container::StyleSheet;
use cosmic::iced_widget::text_input::{Icon, Side};
use cosmic::widget::{
button, column, container, header_bar, icon, list_column, row, scrollable, text, text_input,
Column,
};
use cosmic::{
cosmic_config::{Config, CosmicConfigEntry},
iced::{
@ -18,26 +25,18 @@ use cosmic::{
},
iced_runtime::{command::platform_specific, core::id::Id, Command},
iced_sctk::commands,
iced_style::{
button::StyleSheet as ButtonStyleSheet, container::StyleSheet as ContainerStyleSheet,
},
iced_widget::{
column, container,
core::{
layout, renderer,
widget::{tree, Operation, OperationOutputWrapper, Tree},
Clipboard, Shell, Widget,
},
graphics::image::image_rs::EncodableLayout,
row, scrollable, text, text_input,
text_input::{Icon, Side},
Column,
},
sctk::reexports::client::protocol::wl_data_device_manager::DndAction,
theme,
widget::{button, header_bar, icon, list_column},
Element,
theme, Apply, Element,
};
use std::{
borrow::{Borrow, Cow},
fmt::Debug,
@ -244,32 +243,49 @@ impl Page {
}
has_some = true;
list_column = list_column.add(
row![
icon(info.icon.clone(), 32).style(theme::Svg::Symbolic),
column![
text(info.name.clone()),
text(info.description.clone()).size(10)
]
.spacing(4.0)
.width(Length::Fill),
cosmic::iced::widget::button(text(fl!("add")))
.style(theme::Button::Custom {
active: Box::new(|theme| {
let mut style = theme.active(&theme::Button::Text);
style.text_color = theme.cosmic().accent_color().into();
row::with_children(vec![
icon::from_name(&*info.icon)
.size(32)
.symbolic(true)
.icon()
.into(),
column::with_capacity(2)
.push(text(info.name.clone()))
.push(text(info.description.clone()).size(10))
.spacing(4.0)
.width(Length::Fill)
.into(),
button(text(fl!("add")))
.style(button::Style::Custom {
active: Box::new(|focused, theme| {
let mut style = theme.active(focused, &button::Style::Text);
style.text_color = Some(theme.cosmic().accent_color().into());
style
}),
hover: Box::new(|theme| {
let mut style = theme.hovered(&theme::Button::Text);
style.text_color = theme.cosmic().accent_color().into();
disabled: Box::new(|theme| {
let mut style = theme.disabled(&button::Style::Text);
let mut text_color: Color = theme.cosmic().accent_color().into();
text_color.a *= 0.5;
style.text_color = Some(text_color);
style
})
}),
hovered: Box::new(|focused, theme| {
let mut style = theme.hovered(focused, &theme::Button::Text);
style.text_color = Some(theme.cosmic().accent_color().into());
style
}),
pressed: Box::new(|focused, theme| {
let mut style = theme.pressed(focused, &theme::Button::Text);
style.text_color = Some(theme.cosmic().accent_color().into());
style
}),
})
.padding(8.0)
.on_press(app::Message::PageMessage(msg_map(Message::AddApplet(
info.clone()
)))),
]
info.clone(),
))))
.into(),
])
.padding([0, 32, 0, 32])
.spacing(12)
.align_items(Alignment::Center),
@ -282,49 +298,43 @@ impl Page {
.horizontal_alignment(Horizontal::Center),
);
}
column![
column::with_children(vec![
header_bar()
.title(fl!("add-applet"))
.on_close(app::Message::PageMessage(msg_map(
Message::CloseAppletDialogue
Message::CloseAppletDialogue,
)))
.on_drag(app::Message::PageMessage(msg_map(
Message::DragAppletDialogue
))),
Message::DragAppletDialogue,
)))
.into(),
container(
scrollable(
column![
text(fl!("add-applet")).size(24).width(Length::Fill),
text_input(&fl!("search-applets"), &self.search)
.style(theme::TextInput::Search)
.padding([8, 24])
.icon(Icon {
font: cosmic::iced::Font::default(),
code_point: '🔍',
size: Some(12.0),
spacing: 12.0,
side: Side::Left,
})
column::with_children(vec![
text(fl!("add-applet")).size(24).width(Length::Fill).into(),
text_input::search_input(&fl!("search-applets"), &self.search, None)
.on_input(move |s| {
app::Message::PageMessage(msg_map(Message::Search(s)))
})
.on_paste(move |s| {
app::Message::PageMessage(msg_map(Message::Search(s)))
})
.width(Length::Fixed(312.0)),
list_column
]
.width(Length::Fixed(312.0))
.into(),
list_column.into(),
])
.padding([0, 64, 32, 64])
.align_items(Alignment::Center)
.spacing(8.0)
.spacing(8.0),
)
.width(Length::Fill)
.height(Length::Fill)
.height(Length::Fill),
)
.style(theme::Container::Background)
.width(Length::Fill)
.height(Length::Fill)
]
.into(),
])
.into()
}
@ -497,33 +507,36 @@ pub fn lists<
);
};
let button = cosmic::iced::widget::button(text(fl!("add-applet")))
.style(theme::Button::Secondary)
.padding(8.0);
column![
column![
row![
text(fl!("applets")).width(Length::Fill).size(24),
if page.has_dialogue {
let button = button::standard(fl!("add-applet"));
column::with_children(vec![
column::with_children(vec![
row::with_children(vec![
text(fl!("applets")).width(Length::Fill).size(24).into(),
(if page.has_dialogue {
button
} else {
button.on_press(Message::AddAppletDialogue)
}
],
text(fl!("start-segment")),
})
.into(),
])
.into(),
text(fl!("start-segment")).into(),
AppletReorderList::new(
config
.plugins_wings
.as_ref()
.map(|list| list
.0
.iter()
.filter_map(|id| page
.available_entries
.map(|list| {
list.0
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed))
.collect())
.filter_map(|id| {
page.available_entries
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed)
})
.collect()
})
.unwrap_or_default(),
Some((window::Id(0), APPLET_DND_ICON_ID)),
Message::StartDnd,
@ -533,24 +546,28 @@ pub fn lists<
Message::ReorderStart,
Message::Save,
Message::Cancel,
page.reorder_widget_state.dragged_applet().as_ref()
page.reorder_widget_state.dragged_applet().as_ref(),
)
]
.spacing(8.0),
column![
text(fl!("center-segment")),
.into(),
])
.spacing(8.0)
.into(),
column::with_children(vec![
text(fl!("center-segment")).into(),
AppletReorderList::new(
config
.plugins_center
.as_ref()
.map(|list| list
.iter()
.filter_map(|id| page
.available_entries
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed))
.collect())
.map(|list| {
list.iter()
.filter_map(|id| {
page.available_entries
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed)
})
.collect()
})
.unwrap_or_default(),
Some((window::Id(0), APPLET_DND_ICON_ID)),
Message::StartDnd,
@ -560,25 +577,29 @@ pub fn lists<
Message::ReorderCenter,
Message::Save,
Message::Cancel,
page.reorder_widget_state.dragged_applet().as_ref()
page.reorder_widget_state.dragged_applet().as_ref(),
)
]
.spacing(8.0),
column![
text(fl!("end-segment")),
.into(),
])
.spacing(8.0)
.into(),
column::with_children(vec![
text(fl!("end-segment")).into(),
AppletReorderList::new(
config
.plugins_wings
.as_ref()
.map(|list| list
.1
.iter()
.filter_map(|id| page
.available_entries
.map(|list| {
list.1
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed))
.collect())
.filter_map(|id| {
page.available_entries
.iter()
.find(|e| e.id.as_ref() == id.as_str())
.map(Applet::borrowed)
})
.collect()
})
.unwrap_or_default(),
Some((window::Id(0), APPLET_DND_ICON_ID)),
Message::StartDnd,
@ -588,11 +609,13 @@ pub fn lists<
Message::ReorderEnd,
Message::Save,
Message::Cancel,
page.reorder_widget_state.dragged_applet().as_ref()
page.reorder_widget_state.dragged_applet().as_ref(),
)
]
.spacing(8.0),
]
.into(),
])
.spacing(8.0)
.into(),
])
.padding([0, 16, 0, 16])
.spacing(12.0)
.apply(Element::from)
@ -700,19 +723,27 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
let id_clone = info.id.to_string();
let is_dragged = active_dnd.as_ref().map_or(false, |dnd| dnd.id == info.id);
container(
row![
icon("open-menu-symbolic", 16).style(theme::Svg::Symbolic),
icon(info.icon, 32).style(theme::Svg::Symbolic),
column![text(info.name), text(info.description).size(10)]
row::with_children(vec![
icon::from_name("open-menu-symbolic")
.symbolic(true)
.size(16)
.into(),
icon::from_name(info.icon).size(32).symbolic(true).into(),
column::with_capacity(2)
.spacing(4.0)
.width(Length::Fill),
button(theme::Button::Text)
.icon(theme::Svg::Symbolic, "edit-delete-symbolic", 16)
.on_press(on_remove(id_clone.clone())),
button(theme::Button::Text)
.icon(theme::Svg::Symbolic, "open-menu-symbolic", 16)
.on_press(on_details(id_clone)),
]
.width(Length::Fill)
.push(text(info.name))
.push(text::caption(info.description))
.into(),
button::icon(icon::from_name("edit-delete-symbolic"))
.extra_small()
.on_press(on_remove(id_clone.clone()))
.into(),
button::icon(icon::from_name("open-menu-symbolic"))
.extra_small()
.on_press(on_details(id_clone))
.into(),
])
.spacing(12)
.align_items(Alignment::Center),
)
@ -781,23 +812,28 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
surface_ids: None,
inner: if let Some(info) = state.dragged_applet() {
container(
row![
icon("open-menu-symbolic", 16).style(theme::Svg::Symbolic),
icon(info.icon.into_owned(), 32).style(theme::Svg::Symbolic),
column![text(info.name), text(info.description).size(10)]
row::with_children(vec![
icon::from_name("open-menu-symbolic")
.size(16)
.symbolic(true)
.into(),
icon::from_name(info.icon.into_owned())
.size(32)
.symbolic(true)
.into(),
column::with_capacity(2)
.spacing(4.0)
.width(Length::Fill),
button(theme::Button::Text).icon(
theme::Svg::Symbolic,
"edit-delete-symbolic",
16
),
button(theme::Button::Text).icon(
theme::Svg::Symbolic,
"open-menu-symbolic",
16
),
]
.width(Length::Fill)
.push(text(info.name))
.push(text::caption(info.description))
.into(),
button::icon(icon::from_name("edit-delete-symbolic"))
.extra_small()
.into(),
button::icon(icon::from_name("open-menu-symbolic"))
.extra_small()
.into(),
])
.spacing(12)
.align_items(Alignment::Center),
)
@ -939,6 +975,7 @@ where
renderer: &cosmic::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) -> event::Status {
let mut ret = match self.inner.as_widget_mut().on_event(
&mut tree.children[0],
@ -948,6 +985,7 @@ where
renderer,
clipboard,
shell,
viewport,
) {
event::Status::Captured => return event::Status::Captured,
event::Status::Ignored => event::Status::Ignored,

View file

@ -1,11 +1,12 @@
use cosmic::{
cosmic_config::{self, CosmicConfigEntry},
iced::widget::{button, container, horizontal_space, pick_list, row},
iced::Length,
iced_widget::slider,
sctk::reexports::client::{backend::ObjectId, protocol::wl_output::WlOutput, Proxy},
theme,
widget::{icon, list, settings, text, toggler},
widget::{
button, container, horizontal_space, icon, list, pick_list, row, settings, text, toggler,
},
Element,
};
@ -14,7 +15,7 @@ use cosmic_panel_config::{
AutoHide, CosmicPanelBackground, CosmicPanelConfig, CosmicPanelContainerConfig,
CosmicPanelOuput, PanelAnchor, PanelSize,
};
use cosmic_settings_page::{self as page, section, Section};
use cosmic_settings_page::{self as page, Section};
use std::{borrow::Cow, collections::HashMap};
pub struct PageInner {
@ -149,8 +150,8 @@ pub(crate) fn style<
.add(settings::item(
&descriptions[3],
// TODO custom discrete slider variant
row![
text(fl!("small")),
row::with_children(vec![
text(fl!("small")).into(),
slider(
0..=4,
match panel_config.size {
@ -173,20 +174,22 @@ pub(crate) fn style<
Message::PanelSize(PanelSize::XL)
}
},
),
text(fl!("large"))
]
)
.into(),
text(fl!("large")).into(),
])
.spacing(12),
))
.add(settings::item(
&descriptions[4],
row![
text(fl!("number", HashMap::from_iter(vec![("number", 0)]))),
row::with_children(vec![
text(fl!("number", HashMap::from_iter(vec![("number", 0)]))).into(),
slider(0..=100, (panel_config.opacity * 100.0) as i32, |v| {
Message::Opacity(v as f32 / 100.0)
},),
text(fl!("number", HashMap::from_iter(vec![("number", 100)]))),
]
})
.into(),
text(fl!("number", HashMap::from_iter(vec![("number", 100)]))).into(),
])
.spacing(12),
))
.apply(Element::from)
@ -208,17 +211,18 @@ pub(crate) fn configuration<P: page::Page<crate::pages::Message> + PanelPage>(
.iter()
.find(|(_, v)| v.id == page.applets_page_id())
{
let control = row::with_children(vec![
horizontal_space(Length::Fill).into(),
icon::from_name("go-next-symbolic").size(16).into(),
]);
settings.add(
settings::item::builder(&descriptions[0])
.control(row!(
horizontal_space(Length::Fill),
icon("go-next-symbolic", 20).style(theme::Svg::Symbolic)
))
.control(control)
.spacing(16)
.apply(container)
.style(theme::Container::custom(list::column::style))
.style(theme::Container::custom(list::style))
.apply(button)
.padding(0)
.style(theme::Button::Transparent)
.on_press(crate::pages::Message::Page(panel_applets_entity)),
)

View file

@ -13,7 +13,7 @@ use apply::Apply;
use cosmic::widget::{
list_column,
segmented_button::{self, SingleSelectModel},
settings, toggler,
segmented_selection, settings, text, toggler,
};
use cosmic::{iced::Length, Element};
use cosmic::{iced_core::alignment, iced_runtime::core::image::Handle as ImageHandle};
@ -591,7 +591,7 @@ pub fn settings() -> Section<crate::pages::Message> {
));
children.push(if page.config.same_on_all {
cosmic::widget::text(fl!("all-displays"))
text(fl!("all-displays"))
.font(cosmic::font::FONT_SEMIBOLD)
.horizontal_alignment(alignment::Horizontal::Center)
.vertical_alignment(alignment::Vertical::Center)
@ -602,7 +602,7 @@ pub fn settings() -> Section<crate::pages::Message> {
.height(Length::Fixed(32.0))
.into()
} else {
cosmic::widget::horizontal_segmented_selection(&page.outputs)
segmented_selection::horizontal(&page.outputs)
.on_activate(Message::Output)
.into()
});
@ -669,7 +669,6 @@ pub fn settings() -> Section<crate::pages::Message> {
cosmic::iced::widget::column(children)
.spacing(22)
.max_width(683)
.apply(Element::from)
.map(crate::pages::Message::DesktopWallpaper)
})

View file

@ -2,10 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only
use super::Message;
use apply::Apply;
use cosmic::iced_core::{self, gradient::Linear, Background, BorderRadius, Color, Degrees};
use cosmic::iced_core::{alignment, Length};
use cosmic::iced_runtime::core::image::Handle as ImageHandle;
use cosmic::prelude::*;
use cosmic::widget::{button, container, image, space};
use cosmic::{iced, Element};
use cosmic_settings_desktop::wallpaper;
use slotmap::DefaultKey;
@ -18,9 +19,9 @@ const ROW_SPACING: u16 = 16;
/// A button for selecting a color or gradient.
pub fn color_button(color: wallpaper::Color) -> Element<'static, Message> {
iced::widget::button(color_image(color.clone(), COLOR_WIDTH, COLOR_WIDTH, 8.0))
button(color_image(color.clone(), COLOR_WIDTH, COLOR_WIDTH, 8.0))
.padding(0)
.style(cosmic::theme::Button::Transparent)
.style(button::Style::IconVertical)
.on_press(Message::ColorSelect(color))
.into()
}
@ -32,9 +33,10 @@ pub fn color_image(
height: u16,
border_radius: f32,
) -> Element<'static, Message> {
iced::widget::container(iced::widget::space::Space::new(width, height))
container(space::Space::new(width, height))
.style(cosmic::theme::Container::custom(move |_theme| {
iced::widget::container::Appearance {
container::Appearance {
icon_color: None,
text_color: None,
background: Some(match &color {
wallpaper::Color::Single([r, g, b]) => {
@ -98,9 +100,9 @@ fn flex_select_row<'a>(
}
fn wallpaper_button(handle: &ImageHandle, id: DefaultKey) -> Element<Message> {
let image = iced::widget::image(handle.clone()).apply(iced::Element::from);
let image = image(handle.clone()).apply(iced::Element::from);
iced::widget::button(image)
button(image)
.padding(0)
.style(cosmic::theme::Button::Transparent)
.on_press(Message::Select(id))

View file

@ -6,7 +6,7 @@ use cosmic::{
window, Length,
},
iced_style, theme,
widget::settings,
widget::{button, container, icon, radio, settings},
};
use cosmic_settings_page::{self as page, section, Section};
use slotmap::SlotMap;
@ -68,11 +68,11 @@ fn popover_menu_row(label: String) -> cosmic::Element<'static, Message> {
.style(cosmic::theme::Container::custom(|theme| {
iced_style::container::Appearance {
background: None,
..cosmic::widget::list::column::style(theme)
..cosmic::widget::list::style(theme)
}
}))
.apply(widget::button)
.style(cosmic::theme::Button::Transparent)
.apply(button)
.style(theme::Button::Transparent)
.into()
}
@ -92,7 +92,8 @@ fn popover_menu() -> cosmic::Element<'static, Message> {
.height(Length::Shrink)
.apply(cosmic::widget::container)
.style(cosmic::theme::Container::custom(|theme| {
iced_style::container::Appearance {
container::Appearance {
icon_color: Some(theme.cosmic().background.on.into()),
text_color: Some(theme.cosmic().background.on.into()),
background: Some(iced::Color::from(theme.cosmic().background.base).into()),
border_radius: (12.0).into(),
@ -104,18 +105,14 @@ fn popover_menu() -> cosmic::Element<'static, Message> {
}
fn popover_button(input_source: &InputSource, expanded: bool) -> cosmic::Element<'static, Message> {
let style = if expanded {
cosmic::theme::Svg::SymbolicActive
} else {
cosmic::theme::Svg::Symbolic
};
let on_press = Message::ExpandInputSourcePopover(if expanded {
None
} else {
Some(input_source.id.clone())
});
let button = cosmic::widget::button(cosmic::theme::Button::Secondary)
.icon(style, "open-menu-symbolic", 20)
let button = button::icon(icon::from_name("open-menu-symbolic"))
.extra_small()
.padding(0)
.on_press(on_press);
@ -195,12 +192,9 @@ fn special_char_radio_row<'a>(
value: Option<&'static str>,
current_value: Option<&'a str>,
) -> cosmic::Element<'a, Message> {
settings::item_row(vec![iced::widget::radio(
desc,
value,
Some(current_value),
|_| Message::SpecialCharacterSelect(value),
)
settings::item_row(vec![radio(desc, value, Some(current_value), |_| {
Message::SpecialCharacterSelect(value)
})
.into()])
.into()
}
@ -312,7 +306,7 @@ fn keyboard_shortcuts() -> Section<crate::pages::Message> {
fn go_next_control<Msg: Clone + 'static>() -> cosmic::Element<'static, Msg> {
widget::row!(
horizontal_space(Length::Fill),
cosmic::widget::icon("go-next-symbolic", 20).style(cosmic::theme::Svg::Symbolic)
icon::from_name("go-next-symbolic").size(16).icon(),
)
.into()
}
@ -321,11 +315,10 @@ fn go_next_item<Msg: Clone + 'static>(description: &str, msg: Msg) -> cosmic::El
settings::item(description, go_next_control())
.apply(widget::container)
.style(cosmic::theme::Container::custom(
cosmic::widget::list::column::style,
cosmic::widget::list::style,
))
.apply(widget::button)
.style(cosmic::theme::Button::Transparent)
.padding(0)
.apply(button)
.style(theme::Button::Transparent)
.on_press(msg)
.into()
}

View file

@ -1,7 +1,5 @@
use apply::Apply;
use cosmic::iced::widget;
use cosmic::widget::settings;
use cosmic::Element;
use cosmic::widget::{column, settings};
use cosmic::{Apply, Element};
use cosmic_settings_page::Section;
use cosmic_settings_page::{self as page, section};
use slotmap::SlotMap;
@ -44,7 +42,8 @@ fn shortcuts() -> Section<crate::pages::Message> {
.apply(Element::from)
.map(crate::pages::Message::Input)
*/
widget::column![settings::view_section(&section.title)]
column()
.push(settings::view_section(&section.title))
.apply(Element::from)
.map(crate::pages::Message::Input)
})

View file

@ -1,6 +1,5 @@
use apply::Apply;
use cosmic::iced::widget;
use cosmic::widget::settings;
use cosmic::widget::{self, settings};
use cosmic::Element;
use cosmic_comp_config::input::AccelProfile;
use cosmic_settings_page::Section;

View file

@ -1,6 +1,5 @@
use apply::Apply;
use cosmic::iced::widget;
use cosmic::widget::settings;
use cosmic::widget::{self, settings};
use cosmic::Element;
use cosmic_comp_config::input::AccelProfile;
use cosmic_settings_page::Section;

View file

@ -1,7 +1,7 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
use cosmic::{iced, widget::settings};
use cosmic::widget::{settings, text};
use cosmic_settings_page::{self as page, section, Section};
use slotmap::SlotMap;
@ -39,14 +39,8 @@ fn alerts() -> Section<crate::pages::Message> {
])
.view::<Page>(|_binder, _page, section| {
settings::view_section(&section.title)
.add(settings::item(
&section.descriptions[0],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[1],
iced::widget::text("TODO"),
))
.add(settings::item(&section.descriptions[0], text("TODO")))
.add(settings::item(&section.descriptions[1], text("TODO")))
.into()
})
}
@ -57,10 +51,7 @@ fn applications() -> Section<crate::pages::Message> {
.descriptions(vec![fl!("sound-applications", "desc")])
.view::<Page>(|_binder, _page, section| {
settings::view_section(&section.title)
.add(settings::item(
&section.descriptions[0],
iced::widget::text("TODO"),
))
.add(settings::item(&section.descriptions[0], text("TODO")))
.into()
})
}
@ -75,18 +66,9 @@ fn input() -> Section<crate::pages::Message> {
])
.view::<Page>(|_binder, _page, section| {
settings::view_section(&section.title)
.add(settings::item(
&section.descriptions[0],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[1],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[2],
iced::widget::text("TODO"),
))
.add(settings::item(&section.descriptions[0], text("TODO")))
.add(settings::item(&section.descriptions[1], text("TODO")))
.add(settings::item(&section.descriptions[2], text("TODO")))
.into()
})
}
@ -103,22 +85,10 @@ fn output() -> Section<crate::pages::Message> {
])
.view::<Page>(|_binder, _page, section| {
settings::view_section(&section.title)
.add(settings::item(
&section.descriptions[0],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[1],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[2],
iced::widget::text("TODO"),
))
.add(settings::item(
&section.descriptions[3],
iced::widget::text("TODO"),
))
.add(settings::item(&section.descriptions[0], text("TODO")))
.add(settings::item(&section.descriptions[1], text("TODO")))
.add(settings::item(&section.descriptions[2], text("TODO")))
.add(settings::item(&section.descriptions[3], text("TODO")))
.into()
})
}

View file

@ -80,7 +80,7 @@ fn distributor_logo() -> Section<crate::pages::Message> {
.view::<Page>(|_binder, _page, _section| {
row!(
horizontal_space(Length::Fill),
icon("distributor-logo", 78),
icon::from_name("distributor-logo").size(78).icon(),
horizontal_space(Length::Fill),
)
// Add extra padding to reach 40px from the first section.

View file

@ -5,7 +5,8 @@ use cosmic::{iced_widget::core::BorderRadius, theme};
#[must_use]
pub fn display_container_frame() -> cosmic::theme::Container {
theme::Container::custom(|_theme| cosmic::iced::widget::container::Appearance {
theme::Container::custom(|_theme| cosmic::widget::container::Appearance {
icon_color: None,
text_color: None,
background: Some(cosmic::iced::Background::Color(cosmic::iced::Color::WHITE)),
border_color: cosmic::iced::Color::WHITE,
@ -16,7 +17,8 @@ pub fn display_container_frame() -> cosmic::theme::Container {
#[must_use]
pub fn display_container_screen() -> cosmic::theme::Container {
theme::Container::custom(|_theme| cosmic::iced::widget::container::Appearance {
theme::Container::custom(|_theme| cosmic::widget::container::Appearance {
icon_color: None,
text_color: None,
background: Some(cosmic::iced::Background::Color(cosmic::iced::Color::BLACK)),
border_color: cosmic::iced::Color::BLACK,

View file

@ -2,13 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only
use apply::Apply;
use cosmic::iced::{
self,
widget::{button, column, container, horizontal_space, row, vertical_space, Button},
Length,
use cosmic::iced::Length;
use cosmic::widget::{
button, column, container, divider, horizontal_space, row, settings, text, vertical_space,
};
use cosmic::widget::{divider, icon, list, settings, text};
use cosmic::{theme, Element};
use cosmic::Element;
use cosmic_settings_page as page;
#[must_use]
@ -41,87 +39,19 @@ pub fn search_header<Message>(
column_children.push(vertical_space(Length::Fixed(8.)).into());
column_children.push(divider::horizontal::heavy().into());
column(column_children).into()
column::with_children(column_children).into()
}
#[must_use]
pub fn search_page_link<Message: 'static>(title: &str) -> Button<Message, cosmic::Renderer> {
text(title)
.size(24)
.horizontal_alignment(iced::alignment::Horizontal::Left)
.apply(button)
.style(cosmic::theme::Button::Link)
pub fn search_page_link<Message: 'static>(title: &str) -> button::TextButton<Message> {
button::text(title).style(button::Style::Link)
}
#[must_use]
pub fn page_title<Message: 'static>(page: &page::Info) -> Element<Message> {
row!(
text(page.title.as_str()).size(24),
horizontal_space(Length::Fill)
)
.into()
}
#[must_use]
pub fn parent_page_button<'a, Message: Clone + 'static>(
parent: &'a page::Info,
sub_page: &'a page::Info,
on_press: Message,
) -> Element<'a, Message> {
column!(
button(row!(
icon("go-previous-symbolic", 20).style(theme::Svg::SymbolicLink),
text(parent.title.as_str()).size(14),
))
.padding(0)
.style(theme::Button::Link)
.on_press(on_press),
row!(
text(sub_page.title.as_str()).size(24),
horizontal_space(Length::Fill),
)
.align_items(iced::alignment::Alignment::Center),
)
.spacing(6)
.into()
}
#[must_use]
pub fn sub_page_button(entity: page::Entity, page: &page::Info) -> Element<page::Entity> {
settings::item::builder(page.title.as_str())
.description(page.description.as_str())
.icon(icon(&*page.icon_name, 20).style(theme::Svg::Symbolic))
.control(row!(
horizontal_space(Length::Fill),
icon("go-next-symbolic", 20).style(theme::Svg::Symbolic)
))
.spacing(16)
.apply(container)
.padding([20, 24])
.style(theme::Container::custom(list::column::style))
.apply(button)
.padding(0)
.style(theme::Button::Transparent)
.on_press(entity)
.into()
}
#[must_use]
pub fn sub_page_section(entity: page::Entity, page: &page::Info) -> Element<page::Entity> {
settings::item::builder(page.title.as_str())
.description(page.description.as_str())
.control(row!(
horizontal_space(Length::Fill),
icon("go-next-symbolic", 20).style(theme::Svg::Symbolic)
))
.spacing(16)
.apply(container)
.padding([20, 24])
.style(theme::Container::custom(list::column::style))
.apply(button)
.padding(0)
.style(theme::Button::Transparent)
.on_press(entity)
row::with_capacity(2)
.push(text::title3(page.title.as_str()))
.push(horizontal_space(Length::Fill))
.into()
}
@ -134,15 +64,16 @@ pub fn unimplemented_page<Message: 'static>() -> Element<'static, Message> {
#[must_use]
pub fn display_container<'a, Message: 'a>(widget: Element<'a, Message>) -> Element<'a, Message> {
row!(
horizontal_space(Length::Fill),
container(widget)
.style(crate::theme::display_container_screen())
.apply(container)
.padding(4)
.style(crate::theme::display_container_frame()),
horizontal_space(Length::Fill),
)
.padding([0, 0, 8, 0])
.into()
let display = container(widget)
.style(crate::theme::display_container_screen())
.apply(container)
.padding(4)
.style(crate::theme::display_container_frame());
row::with_capacity(3)
.push(horizontal_space(Length::Fill))
.push(display)
.push(horizontal_space(Length::Fill))
.padding([0, 0, 8, 0])
.into()
}

View file

@ -85,6 +85,11 @@ impl<Message: 'static> Binder<Message> {
.and_then(|storage| storage.remove(id));
}
#[must_use]
pub fn find_page_by_id(&self, id: &str) -> Option<(crate::Entity, &Info)> {
self.info.iter().find(|(_id, info)| info.id == id)
}
/// Registers a new page in the settings panel.
pub fn register<P: AutoBind<Message>>(&mut self) -> crate::Insert<Message> {
let page = P::default();