feat: partial implementation of wallpaper settings

Will take some time to refactor the rest
This commit is contained in:
Michael Aaron Murphy 2023-05-22 17:26:14 +02:00
parent 14a4a23bc9
commit a4eee2186c
No known key found for this signature in database
GPG key ID: B2732D4240C9212C
14 changed files with 375 additions and 80 deletions

View file

@ -235,19 +235,16 @@ impl Application for SettingsApp {
Message::None | Message::Search(_) => {}
Message::PageMessage(message) => match message {
crate::pages::Message::About(message) => {
if let Some(page) = self.pages.page_mut::<system::about::Page>() {
page.update(message);
}
page::update!(self.pages, message, system::about::Page);
}
crate::pages::Message::DateAndTime(message) => {
if let Some(page) = self.pages.page_mut::<time::date::Page>() {
page.update(message);
}
page::update!(self.pages, message, time::date::Page);
}
crate::pages::Message::Desktop(message) => {
if let Some(page) = self.pages.page_mut::<desktop::Page>() {
page.update(message);
}
page::update!(self.pages, message, desktop::Page);
}
crate::pages::Message::DesktopWallpaper(message) => {
page::update!(self.pages, message, desktop::wallpaper::Page);
}
crate::pages::Message::External { .. } => {
todo!("external plugins not supported yet");
@ -457,7 +454,10 @@ impl SettingsApp {
);
}
settings::view_column(column_widgets).into()
settings::view_column(column_widgets)
.max_width(683)
.padding(0)
.into()
}
fn search_changed(&mut self, phrase: String) {

View file

@ -52,8 +52,8 @@ pub fn main() -> color_eyre::Result<()> {
let localizer = crate::localize::localizer();
let requested_languages = DesktopLanguageRequester::requested_languages();
if let Err(error) = localizer.select(&requested_languages) {
eprintln!("error while loading fluent localizations: {error}");
if let Err(why) = localizer.select(&requested_languages) {
tracing::error!(%why, "error while loading fluent localizations");
}
cosmic::settings::set_default_icon_theme("Pop");

View file

@ -19,8 +19,6 @@ pub struct Page {
pub show_applications_button: bool,
pub show_minimize_button: bool,
pub show_maximize_button: bool,
pub slideshow: bool,
pub same_background: bool,
}
impl page::Page<crate::pages::Message> for Page {
@ -39,10 +37,8 @@ impl page::AutoBind<crate::pages::Message> for Page {
}
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub enum Message {
Slideshow(bool),
SameBackground(bool),
ShowWorkspacesButton(bool),
ShowApplicationsButton(bool),
ShowMinimizeButton(bool),
@ -53,12 +49,10 @@ pub enum Message {
impl Page {
pub fn update(&mut self, message: Message) {
match message {
Message::SameBackground(value) => self.same_background = value,
Message::ShowApplicationsButton(value) => self.show_applications_button = value,
Message::ShowMaximizeButton(value) => self.show_maximize_button = value,
Message::ShowMinimizeButton(value) => self.show_minimize_button = value,
Message::ShowWorkspacesButton(value) => self.show_workspaces_button = value,
Message::Slideshow(value) => self.slideshow = value,
Message::TopLeftHotCorner(value) => self.top_left_hot_corner = value,
}
}

View file

@ -1,21 +1,74 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
use super::Message;
use std::{path::PathBuf, time::Instant};
use apply::Apply;
use cosmic::{
iced::widget::{column, container, horizontal_space, image, row, svg, text},
iced::alignment::Horizontal,
iced::widget::{column, container, horizontal_space, row, text},
iced::Length,
iced_runtime::core::image::Handle as ImageHandle,
theme,
widget::{list_column, settings, toggler},
Element,
};
use cosmic_settings_desktop::wallpaper::{self, Entry, Output};
use cosmic_settings_page::Section;
use cosmic_settings_page::{self as page, section};
use slotmap::SlotMap;
use slotmap::{DefaultKey, SecondaryMap, SlotMap};
#[derive(Default)]
pub struct Page;
#[derive(Clone, Debug)]
pub enum Message {
SameBackground(bool),
Select(DefaultKey),
Slideshow(bool),
Update((wallpaper::Config, Context)),
}
pub struct Page {
pub config: wallpaper::Config,
pub selection: Context,
pub same_background: bool,
pub slideshow: bool,
}
impl Default for Page {
fn default() -> Self {
Page {
config: wallpaper::Config::default(),
selection: Context::default(),
same_background: true,
slideshow: false,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Context {
active: DefaultKey,
handles: SlotMap<DefaultKey, ImageHandle>,
paths: SecondaryMap<DefaultKey, PathBuf>,
}
impl Page {
pub fn update(&mut self, message: Message) {
match message {
Message::SameBackground(value) => self.same_background = value,
Message::Select(id) => {
if let Some(path) = self.selection.paths.get(id) {
wallpaper::set(&mut self.config, Entry::new(Output::All, path.to_owned()));
self.selection.active = id;
}
}
Message::Slideshow(value) => self.slideshow = value,
Message::Update((config, selection)) => {
self.config = config;
self.selection = selection;
}
}
}
}
impl page::Page<crate::pages::Message> for Page {
fn content(
@ -30,6 +83,32 @@ impl page::Page<crate::pages::Message> for Page {
.title(fl!("wallpaper"))
.description(fl!("wallpaper", "desc"))
}
fn load(&self, _page: page::Entity) -> Option<page::Task<crate::pages::Message>> {
Some(Box::pin(async move {
let config = wallpaper::config();
let mut backgrounds = wallpaper::load_each_from_path("/usr/share/backgrounds".into());
let mut update = Context::default();
let start = Instant::now();
while let Some((path, image)) = backgrounds.recv().await {
let handle =
ImageHandle::from_pixels(image.width(), image.height(), image.into_vec());
let id = update.handles.insert(handle);
update.paths.insert(id, path);
}
tracing::info!(
"loaded wallpapers in {:?}",
Instant::now().duration_since(start)
);
crate::pages::Message::DesktopWallpaper(Message::Update((config, update)))
}))
}
}
impl page::AutoBind<crate::pages::Message> for Page {}
@ -42,57 +121,84 @@ pub fn settings() -> Section<crate::pages::Message> {
fl!("wallpaper", "slide"),
fl!("wallpaper", "change"),
])
.view::<Page>(|binder, _page, section| {
let desktop = binder
.page::<super::Page>()
.expect("desktop page not found");
.view::<Page>(|_binder, page, section| {
let descriptions = &section.descriptions;
let image_paths: Vec<std::path::PathBuf> = Vec::new();
let mut image_column = Vec::with_capacity(image_paths.len() / 4);
for chunk in image_paths.chunks(4) {
let mut image_row = Vec::with_capacity(chunk.len());
for image_path in chunk.iter() {
image_row.push(if image_path.ends_with(".svg") {
svg(svg::Handle::from_path(image_path))
.width(Length::Fixed(150.))
.into()
} else {
image(image_path).width(Length::Fixed(150.)).into()
});
let mut image_column = Vec::with_capacity(page.selection.handles.len() / 4);
let mut image_handles = page.selection.handles.iter();
while let Some((id, handle)) = image_handles.next() {
let mut image_row = Vec::with_capacity(4);
image_row.push(wallpaper_button(handle, id));
for (id, handle) in image_handles.by_ref().take(3) {
image_row.push(wallpaper_button(handle, id));
}
image_column.push(row(image_row).spacing(16).into());
}
let children = vec![
row!(
let mut children = Vec::with_capacity(3);
if let Some(image) = page.selection.handles.get(page.selection.active) {
let display_preview = row!(
horizontal_space(Length::Fill),
container(
image("/usr/share/backgrounds/pop/kate-hazen-COSMIC-desktop-wallpaper.png")
.width(Length::Fixed(300.))
cosmic::iced::widget::image(image.clone()).width(Length::Fixed(300.0))
)
.padding(4)
.style(theme::Container::Background),
horizontal_space(Length::Fill),
)
.into(),
.padding([0, 0, 8, 0])
.into();
children.push(display_preview);
}
children.push(
cosmic::widget::text("All Displays")
.horizontal_alignment(Horizontal::Center)
.width(Length::Fill)
.apply(cosmic::iced::widget::container)
.width(Length::Fill)
.padding([0, 0, 16, 0])
.into(),
);
children.push(
list_column()
.add(settings::item(
&descriptions[0],
toggler(None, desktop.same_background, Message::SameBackground),
toggler(None, page.same_background, Message::SameBackground),
))
.add(settings::item(&descriptions[1], text("TODO")))
.add(settings::item(
&descriptions[2],
toggler(None, desktop.slideshow, Message::Slideshow),
toggler(None, page.slideshow, Message::Slideshow),
))
.into(),
column(image_column).spacing(16).into(),
];
);
settings::view_column(children)
children.push(column(image_column).spacing(12).padding(0).into());
cosmic::iced::widget::column(children)
.spacing(22)
.padding(0)
.max_width(683)
.apply(Element::from)
.map(crate::pages::Message::Desktop)
.map(crate::pages::Message::DesktopWallpaper)
})
}
pub fn wallpaper_button(handle: &ImageHandle, id: DefaultKey) -> Element<Message> {
let image = cosmic::iced::widget::image(handle.clone()).apply(cosmic::iced::Element::from);
cosmic::iced::widget::button(image)
.width(Length::Fixed(158.0))
.height(Length::Fixed(105.0))
.style(cosmic::theme::Button::Transparent)
.on_press(Message::Select(id))
.into()
}

View file

@ -15,6 +15,7 @@ pub enum Message {
DateAndTime(time::date::Message),
Desktop(desktop::Message),
Panel(desktop::panel::Message),
DesktopWallpaper(desktop::wallpaper::Message),
External { id: String, message: Vec<u8> },
Page(Entity),
}

View file

@ -25,7 +25,7 @@ pub fn search_header<Message>(
column_children.push(
text(parent_meta.title.as_str())
.size(16)
.size(14)
.apply(container)
.padding([0, 0, 0, 6])
.into(),
@ -47,7 +47,7 @@ pub fn search_header<Message>(
#[must_use]
pub fn search_page_link<Message: 'static>(title: &str) -> Button<Message, cosmic::Renderer> {
text(title)
.size(32)
.size(24)
.horizontal_alignment(iced::alignment::Horizontal::Left)
.apply(button)
.style(cosmic::theme::Button::Link)
@ -56,7 +56,7 @@ pub fn search_page_link<Message: 'static>(title: &str) -> Button<Message, cosmic
#[must_use]
pub fn page_title<Message: 'static>(page: &page::Info) -> Element<Message> {
row!(
text(page.title.as_str()).size(32),
text(page.title.as_str()).size(24),
horizontal_space(Length::Fill)
)
.into()
@ -71,13 +71,13 @@ pub fn parent_page_button<'a, Message: Clone + 'static>(
column!(
button(row!(
icon("go-previous-symbolic", 20).style(theme::Svg::SymbolicLink),
text(parent.title.as_str()).size(20),
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(32),
text(sub_page.title.as_str()).size(24),
horizontal_space(Length::Fill),
)
.align_items(iced::alignment::Alignment::Center),