feat(wallpaper): color dialog integration
This commit is contained in:
parent
daa730682a
commit
5f089ef9a3
4 changed files with 204 additions and 51 deletions
|
|
@ -503,16 +503,19 @@ impl cosmic::Application for SettingsApp {
|
||||||
{
|
{
|
||||||
return page.dnd_icon();
|
return page.dnd_icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(page)) = (id == *applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID)
|
if let Some(Some(page)) = (id == *applets_inner::ADD_PANEL_APPLET_DIALOGUE_ID)
|
||||||
.then(|| self.pages.page::<applets_inner::Page>())
|
.then(|| self.pages.page::<applets_inner::Page>())
|
||||||
{
|
{
|
||||||
return page.add_applet_view(crate::pages::Message::PanelApplet);
|
return page.add_applet_view(crate::pages::Message::PanelApplet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(page)) = (id == *appearance::COLOR_PICKER_DIALOG_ID)
|
if let Some(Some(page)) = (id == *appearance::COLOR_PICKER_DIALOG_ID)
|
||||||
.then(|| self.pages.page::<appearance::Page>())
|
.then(|| self.pages.page::<appearance::Page>())
|
||||||
{
|
{
|
||||||
return page.color_picker_view();
|
return page.color_picker_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(page)) =
|
if let Some(Some(page)) =
|
||||||
(id == *ADD_DOCK_APPLET_DIALOGUE_ID).then(|| self.pages.page::<dock::applets::Page>())
|
(id == *ADD_DOCK_APPLET_DIALOGUE_ID).then(|| self.pages.page::<dock::applets::Page>())
|
||||||
{
|
{
|
||||||
|
|
@ -520,17 +523,25 @@ impl cosmic::Application for SettingsApp {
|
||||||
crate::pages::Message::DockApplet(dock::applets::Message(msg))
|
crate::pages::Message::DockApplet(dock::applets::Message(msg))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(page)) = (id == *keyboard::ADD_INPUT_SOURCE_DIALOGUE_ID)
|
if let Some(Some(page)) = (id == *keyboard::ADD_INPUT_SOURCE_DIALOGUE_ID)
|
||||||
.then(|| self.pages.page::<input::Page>())
|
.then(|| self.pages.page::<input::Page>())
|
||||||
{
|
{
|
||||||
return page.add_input_source_view();
|
return page.add_input_source_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(page)) = (id == *keyboard::SPECIAL_CHARACTER_DIALOGUE_ID)
|
if let Some(Some(page)) = (id == *keyboard::SPECIAL_CHARACTER_DIALOGUE_ID)
|
||||||
.then(|| self.pages.page::<input::Page>())
|
.then(|| self.pages.page::<input::Page>())
|
||||||
{
|
{
|
||||||
return page.special_character_key_view();
|
return page.special_character_key_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(page) = self.pages.page::<desktop::wallpaper::Page>() {
|
||||||
|
if id == page.color_dialog {
|
||||||
|
return page.show_color_dialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
panic!("unknown window ID: {id:?}");
|
panic!("unknown window ID: {id:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const RECENT_FOLDERS: &str = "recent-folders";
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
context: Option<cosmic_config::Config>,
|
context: Option<cosmic_config::Config>,
|
||||||
current_folder: Option<PathBuf>,
|
pub(super) current_folder: Option<PathBuf>,
|
||||||
custom_colors: Vec<wallpaper::Color>,
|
custom_colors: Vec<wallpaper::Color>,
|
||||||
custom_images: Vec<PathBuf>,
|
custom_images: Vec<PathBuf>,
|
||||||
recent_folders: VecDeque<PathBuf>,
|
recent_folders: VecDeque<PathBuf>,
|
||||||
|
|
@ -34,8 +34,8 @@ impl Config {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(path) = dbg!(context.get::<PathBuf>(CURRENT_FOLDER)) {
|
if let Ok(path) = context.get::<Option<PathBuf>>(CURRENT_FOLDER) {
|
||||||
config.current_folder = Some(path);
|
config.current_folder = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(colors) = context.get::<Vec<wallpaper::Color>>(CUSTOM_COLORS) {
|
if let Ok(colors) = context.get::<Vec<wallpaper::Color>>(CUSTOM_COLORS) {
|
||||||
|
|
@ -59,7 +59,12 @@ impl Config {
|
||||||
pub fn current_folder(&self) -> &Path {
|
pub fn current_folder(&self) -> &Path {
|
||||||
self.current_folder
|
self.current_folder
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or(Path::new("/usr/share/backgrounds/"))
|
.unwrap_or(Self::default_folder())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn default_folder() -> &'static Path {
|
||||||
|
Path::new("/usr/share/backgrounds/")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the current background folder
|
/// Sets the current background folder
|
||||||
|
|
@ -67,9 +72,12 @@ impl Config {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the on-disk configuration could not be updated.
|
/// Returns an error if the on-disk configuration could not be updated.
|
||||||
pub fn set_current_folder(&mut self, folder: PathBuf) -> Result<(), cosmic_config::Error> {
|
pub fn set_current_folder(
|
||||||
|
&mut self,
|
||||||
|
folder: Option<PathBuf>,
|
||||||
|
) -> Result<(), cosmic_config::Error> {
|
||||||
let result = self.update(CURRENT_FOLDER, &folder);
|
let result = self.update(CURRENT_FOLDER, &folder);
|
||||||
self.current_folder = Some(folder);
|
self.current_folder = folder;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,12 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
use cosmic::{iced::Length, Element};
|
use cosmic::iced::{wayland::actions::window::SctkWindowSettings, window, Color, Length};
|
||||||
use cosmic::{iced_core::alignment, iced_runtime::core::image::Handle as ImageHandle};
|
use cosmic::iced_sctk::commands::window::{close_window, get_window};
|
||||||
|
use cosmic::{
|
||||||
|
iced_core::{alignment, layout},
|
||||||
|
iced_runtime::core::image::Handle as ImageHandle,
|
||||||
|
};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
widget::{
|
widget::{
|
||||||
button, dropdown, list_column, row,
|
button, dropdown, list_column, row,
|
||||||
|
|
@ -23,6 +27,10 @@ use cosmic::{
|
||||||
},
|
},
|
||||||
Command,
|
Command,
|
||||||
};
|
};
|
||||||
|
use cosmic::{
|
||||||
|
widget::{color_picker::ColorPickerUpdate, ColorPickerModel},
|
||||||
|
Element,
|
||||||
|
};
|
||||||
use cosmic_settings_desktop::wallpaper::{self, Entry, ScalingMode};
|
use cosmic_settings_desktop::wallpaper::{self, Entry, ScalingMode};
|
||||||
use cosmic_settings_page::Section;
|
use cosmic_settings_page::Section;
|
||||||
use cosmic_settings_page::{self as page, section};
|
use cosmic_settings_page::{self as page, section};
|
||||||
|
|
@ -50,11 +58,12 @@ pub type Image = ImageBuffer<Rgba<u8>, Vec<u8>>;
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
ChangeFolder(Context),
|
ChangeFolder(Context),
|
||||||
ColorAdd(wallpaper::Color),
|
|
||||||
ColorAddDialog,
|
ColorAddDialog,
|
||||||
|
ColorDialogUpdate(ColorPickerUpdate),
|
||||||
ColorRemove(wallpaper::Color),
|
ColorRemove(wallpaper::Color),
|
||||||
ChangeCategory(Category),
|
ChangeCategory(Category),
|
||||||
ColorSelect(wallpaper::Color),
|
ColorSelect(wallpaper::Color),
|
||||||
|
DragColorDialog,
|
||||||
Fit(usize),
|
Fit(usize),
|
||||||
ImageAdd(Option<Arc<(PathBuf, Image, Image)>>),
|
ImageAdd(Option<Arc<(PathBuf, Image, Image)>>),
|
||||||
ImageAddDialog,
|
ImageAddDialog,
|
||||||
|
|
@ -79,6 +88,8 @@ pub struct Page {
|
||||||
pub background_service_config: wallpaper::Config,
|
pub background_service_config: wallpaper::Config,
|
||||||
pub cached_display_handle: Option<ImageHandle>,
|
pub cached_display_handle: Option<ImageHandle>,
|
||||||
pub categories: dropdown::multi::Model<String, Category>,
|
pub categories: dropdown::multi::Model<String, Category>,
|
||||||
|
pub color_dialog: window::Id,
|
||||||
|
pub color_model: ColorPickerModel,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub fit_options: Vec<String>,
|
pub fit_options: Vec<String>,
|
||||||
pub outputs: SingleSelectModel,
|
pub outputs: SingleSelectModel,
|
||||||
|
|
@ -173,6 +184,8 @@ impl Default for Page {
|
||||||
categories
|
categories
|
||||||
},
|
},
|
||||||
background_service_config: wallpaper::Config::default(),
|
background_service_config: wallpaper::Config::default(),
|
||||||
|
color_dialog: window::Id::unique(),
|
||||||
|
color_model: ColorPickerModel::new(fl!("hex"), fl!("rgb"), None, Some(Color::WHITE)),
|
||||||
config: Config::new(),
|
config: Config::new(),
|
||||||
fit_options: vec![fl!("fit-to-screen"), fl!("stretch"), fl!("zoom")],
|
fit_options: vec![fl!("fit-to-screen"), fl!("stretch"), fl!("zoom")],
|
||||||
outputs: SingleSelectModel::default(),
|
outputs: SingleSelectModel::default(),
|
||||||
|
|
@ -204,11 +217,6 @@ impl Default for Page {
|
||||||
selection: Context::default(),
|
selection: Context::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sync custom colors from config.
|
|
||||||
for color in page.config.custom_colors() {
|
|
||||||
page.selection.add_custom_color(color.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
page.assign_recent_folders();
|
page.assign_recent_folders();
|
||||||
|
|
||||||
page
|
page
|
||||||
|
|
@ -355,19 +363,13 @@ impl Page {
|
||||||
wallpaper::set(&mut self.background_service_config, entry);
|
wallpaper::set(&mut self.background_service_config, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates configuration for background image.
|
/// Locate the ID of a background that's already stored in memory
|
||||||
fn config_background_entry(&self, output: String, path: PathBuf) -> Option<Entry> {
|
fn background_id_from_path(&self, path: &Path) -> Option<DefaultKey> {
|
||||||
let scaling_mode = match self.selected_fit {
|
self.selection
|
||||||
FIT => ScalingMode::Fit([0.0, 0.0, 0.0]),
|
.paths
|
||||||
STRETCH => ScalingMode::Stretch,
|
.iter()
|
||||||
ZOOM => ScalingMode::Zoom,
|
.find(|(_id, background)| *background == path)
|
||||||
_ => return None,
|
.map(|(id, _)| id)
|
||||||
};
|
|
||||||
|
|
||||||
Entry::new(output, wallpaper::Source::Path(path))
|
|
||||||
.scaling_mode(scaling_mode)
|
|
||||||
.rotation_frequency(self.rotation_frequency)
|
|
||||||
.apply(Some)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates configuration from the background service.
|
/// Updates configuration from the background service.
|
||||||
|
|
@ -405,7 +407,7 @@ impl Page {
|
||||||
self.select_background_entry(&entry);
|
self.select_background_entry(&entry);
|
||||||
|
|
||||||
if let Some(current) = entry_directory(self.config.current_folder(), &entry) {
|
if let Some(current) = entry_directory(self.config.current_folder(), &entry) {
|
||||||
if let Err(why) = self.config.set_current_folder(current) {
|
if let Err(why) = self.config.set_current_folder(Some(current)) {
|
||||||
tracing::error!(?why, "cannot set current folder");
|
tracing::error!(?why, "cannot set current folder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -423,7 +425,7 @@ impl Page {
|
||||||
|
|
||||||
if let Some(current) = entry_directory(self.config.current_folder(), background)
|
if let Some(current) = entry_directory(self.config.current_folder(), background)
|
||||||
{
|
{
|
||||||
if let Err(why) = self.config.set_current_folder(current) {
|
if let Err(why) = self.config.set_current_folder(Some(current)) {
|
||||||
tracing::error!(?why, "cannot set current folder");
|
tracing::error!(?why, "cannot set current folder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -445,7 +447,18 @@ impl Page {
|
||||||
|
|
||||||
match category {
|
match category {
|
||||||
Category::Backgrounds => {
|
Category::Backgrounds => {
|
||||||
self.select_first_background();
|
if self.config.current_folder.is_some() {
|
||||||
|
let _ = self.config.set_current_folder(None);
|
||||||
|
command = cosmic::command::future(async move {
|
||||||
|
crate::app::Message::PageMessage(crate::pages::Message::DesktopWallpaper(
|
||||||
|
Message::ChangeFolder(
|
||||||
|
change_folder(Config::default_folder().to_owned()).await,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.select_first_background();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Category::Colors => {
|
Category::Colors => {
|
||||||
|
|
@ -455,7 +468,7 @@ impl Page {
|
||||||
|
|
||||||
Category::RecentFolder(id) => {
|
Category::RecentFolder(id) => {
|
||||||
if let Some(path) = self.config.recent_folders().get(id).cloned() {
|
if let Some(path) = self.config.recent_folders().get(id).cloned() {
|
||||||
if let Err(why) = self.config.set_current_folder(path.clone()) {
|
if let Err(why) = self.config.set_current_folder(Some(path.clone())) {
|
||||||
tracing::error!(?path, ?why, "failed to set current folder");
|
tracing::error!(?path, ?why, "failed to set current folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,6 +508,21 @@ impl Page {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates configuration for background image.
|
||||||
|
fn config_background_entry(&self, output: String, path: PathBuf) -> Option<Entry> {
|
||||||
|
let scaling_mode = match self.selected_fit {
|
||||||
|
FIT => ScalingMode::Fit([0.0, 0.0, 0.0]),
|
||||||
|
STRETCH => ScalingMode::Stretch,
|
||||||
|
ZOOM => ScalingMode::Zoom,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry::new(output, wallpaper::Source::Path(path))
|
||||||
|
.scaling_mode(scaling_mode)
|
||||||
|
.rotation_frequency(self.rotation_frequency)
|
||||||
|
.apply(Some)
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn display_image_view(&self) -> cosmic::Element<Message> {
|
pub fn display_image_view(&self) -> cosmic::Element<Message> {
|
||||||
match self.cached_display_handle {
|
match self.cached_display_handle {
|
||||||
|
|
@ -509,6 +537,44 @@ impl Page {
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn update(&mut self, message: Message) -> Command<crate::app::Message> {
|
pub fn update(&mut self, message: Message) -> Command<crate::app::Message> {
|
||||||
match message {
|
match message {
|
||||||
|
Message::DragColorDialog => {
|
||||||
|
return cosmic::iced_sctk::commands::window::start_drag_window(self.color_dialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::ColorDialogUpdate(update) => {
|
||||||
|
let cmd = match update {
|
||||||
|
ColorPickerUpdate::AppliedColor
|
||||||
|
| ColorPickerUpdate::Cancel
|
||||||
|
| ColorPickerUpdate::Reset => {
|
||||||
|
if let Some(color) = self.color_model.get_applied_color() {
|
||||||
|
let color = wallpaper::Color::Single([color.r, color.g, color.b]);
|
||||||
|
|
||||||
|
if let Err(why) = self.config.add_custom_color(color.clone()) {
|
||||||
|
tracing::error!(?why, "could not set custom color");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.selection.add_custom_color(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
close_window(self.color_dialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorPickerUpdate::ActionFinished => {
|
||||||
|
let _res = self
|
||||||
|
.color_model
|
||||||
|
.update::<crate::app::Message>(ColorPickerUpdate::AppliedColor);
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Command::none(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Command::batch(vec![
|
||||||
|
cmd,
|
||||||
|
self.color_model.update::<crate::app::Message>(update),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
Message::ChangeFolder(mut context) => {
|
Message::ChangeFolder(mut context) => {
|
||||||
// Reassign custom colors and images to the new context.
|
// Reassign custom colors and images to the new context.
|
||||||
std::mem::swap(&mut context, &mut self.selection);
|
std::mem::swap(&mut context, &mut self.selection);
|
||||||
|
|
@ -531,14 +597,9 @@ impl Page {
|
||||||
|
|
||||||
self.select_first_background();
|
self.select_first_background();
|
||||||
}
|
}
|
||||||
Message::ColorAdd(color) => {
|
|
||||||
if let Err(why) = self.config.add_custom_color(color) {
|
|
||||||
tracing::error!(?why, "could not set custom color");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Message::ColorAddDialog => {
|
Message::ColorAddDialog => {
|
||||||
unimplemented!();
|
return get_window(color_picker_window_settings(self.color_dialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::ColorRemove(color) => {
|
Message::ColorRemove(color) => {
|
||||||
|
|
@ -625,7 +686,22 @@ impl Page {
|
||||||
self.background_service_config_update(update.0, update.1, update.2);
|
self.background_service_config_update(update.0, update.1, update.2);
|
||||||
self.config_apply();
|
self.config_apply();
|
||||||
|
|
||||||
// Load custom content
|
// Sync custom colors from config.
|
||||||
|
for color in self.config.custom_colors() {
|
||||||
|
self.selection.add_custom_color(color.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default selection if an image was selected.
|
||||||
|
if let Choice::Background(_) | Choice::Slideshow = self.selection.active {
|
||||||
|
let folder = self.config.current_folder();
|
||||||
|
for (id, recent) in self.config.recent_folders().iter().enumerate() {
|
||||||
|
if recent == folder {
|
||||||
|
self.categories.selected = Some(Category::RecentFolder(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load preview images for each custom image stored in the on-disk config.
|
||||||
return cosmic::command::batch(self.config.custom_images().iter().cloned().map(
|
return cosmic::command::batch(self.config.custom_images().iter().cloned().map(
|
||||||
|path| {
|
|path| {
|
||||||
cosmic::command::future(async move {
|
cosmic::command::future(async move {
|
||||||
|
|
@ -717,13 +793,13 @@ impl Page {
|
||||||
self.cache_display_image();
|
self.cache_display_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locate the ID of a background that's already stored in memory
|
pub fn show_color_dialog(&self) -> Element<crate::app::Message> {
|
||||||
fn background_id_from_path(&self, path: &Path) -> Option<DefaultKey> {
|
color_picker_view(
|
||||||
self.selection
|
&self.color_model,
|
||||||
.paths
|
Message::DragColorDialog,
|
||||||
.iter()
|
Message::ColorDialogUpdate,
|
||||||
.find(|(_id, background)| *background == path)
|
)
|
||||||
.map(|(id, _)| id)
|
.map(|m| crate::app::Message::PageMessage(crate::pages::Message::DesktopWallpaper(m)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -754,7 +830,7 @@ pub struct Context {
|
||||||
impl Context {
|
impl Context {
|
||||||
fn add_custom_color(&mut self, color: wallpaper::Color) {
|
fn add_custom_color(&mut self, color: wallpaper::Color) {
|
||||||
if !self.custom_colors.contains(&color) {
|
if !self.custom_colors.contains(&color) {
|
||||||
self.add_custom_color(color);
|
self.custom_colors.push(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -923,7 +999,11 @@ pub fn settings() -> Section<crate::pages::Message> {
|
||||||
(fl!("add-image"), Message::ImageAddDialog)
|
(fl!("add-image"), Message::ImageAddDialog)
|
||||||
};
|
};
|
||||||
|
|
||||||
button::link(text).on_press(message)
|
button::link(text)
|
||||||
|
.trailing_icon(true)
|
||||||
|
.on_press(message)
|
||||||
|
.apply(cosmic::widget::container)
|
||||||
|
.align_y(alignment::Vertical::Bottom)
|
||||||
};
|
};
|
||||||
|
|
||||||
children.push(
|
children.push(
|
||||||
|
|
@ -985,3 +1065,60 @@ fn entry_directory(current_folder: &Path, entry: &wallpaper::Entry) -> Option<Pa
|
||||||
wallpaper::Source::Color(_) => PathBuf::from(current_folder),
|
wallpaper::Source::Color(_) => PathBuf::from(current_folder),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn color_picker_window_settings(window_id: window::Id) -> SctkWindowSettings {
|
||||||
|
SctkWindowSettings {
|
||||||
|
window_id,
|
||||||
|
app_id: Some("com.system76.CosmicSettings".to_string()),
|
||||||
|
title: Some(fl!("color-picker")),
|
||||||
|
parent: Some(window::Id::MAIN),
|
||||||
|
autosize: false,
|
||||||
|
size_limits: layout::Limits::NONE
|
||||||
|
.min_width(300.0)
|
||||||
|
.max_width(800.0)
|
||||||
|
.min_height(520.0)
|
||||||
|
.max_height(520.0),
|
||||||
|
size: (300, 520),
|
||||||
|
resizable: Some(8.0),
|
||||||
|
client_decorations: true,
|
||||||
|
transparent: true,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Reuse with the appearance page
|
||||||
|
pub fn color_picker_view<Message: Clone + 'static>(
|
||||||
|
model: &ColorPickerModel,
|
||||||
|
on_drag: Message,
|
||||||
|
on_message: fn(ColorPickerUpdate) -> Message,
|
||||||
|
) -> Element<Message> {
|
||||||
|
let header = cosmic::widget::header_bar()
|
||||||
|
.title(fl!("color-picker"))
|
||||||
|
.on_close(on_message(ColorPickerUpdate::AppliedColor))
|
||||||
|
.on_drag(on_drag);
|
||||||
|
|
||||||
|
let content = cosmic::widget::container(
|
||||||
|
model
|
||||||
|
.builder(on_message)
|
||||||
|
.width(Length::Fixed(254.0))
|
||||||
|
.height(Length::Fixed(174.0))
|
||||||
|
.reset_label(fl!("reset-to-default"))
|
||||||
|
.build(
|
||||||
|
fl!("recent-colors"),
|
||||||
|
fl!("copy-to-clipboard"),
|
||||||
|
fl!("copied-to-clipboard"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.center_x()
|
||||||
|
.style(cosmic::theme::style::Container::Background);
|
||||||
|
|
||||||
|
cosmic::widget::column::with_capacity(2)
|
||||||
|
.push(header)
|
||||||
|
.push(content)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.align_items(cosmic::iced_core::Alignment::Center)
|
||||||
|
.apply(Element::from)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ use image::{DynamicImage, ImageBuffer, Rgba, RgbaImage};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{hash_map::DefaultHasher, BTreeSet, HashMap},
|
collections::{hash_map::DefaultHasher, BTreeSet, HashMap},
|
||||||
fs::DirEntry,
|
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
io::Read,
|
io::Read,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|
@ -97,8 +96,6 @@ pub fn cache_dir() -> Option<PathBuf> {
|
||||||
/// Loads wallpapers in parallel by spawning tasks with a rayon thread pool.
|
/// Loads wallpapers in parallel by spawning tasks with a rayon thread pool.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn load_each_from_path(path: PathBuf) -> Receiver<(PathBuf, RgbaImage, RgbaImage)> {
|
pub fn load_each_from_path(path: PathBuf) -> Receiver<(PathBuf, RgbaImage, RgbaImage)> {
|
||||||
let cache_dir = cache_dir();
|
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(1);
|
let (tx, rx) = mpsc::channel(1);
|
||||||
|
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
|
|
@ -187,7 +184,7 @@ pub async fn load_image_with_thumbnail(
|
||||||
let _res = tx.send(Some((path, display_thumbnail, selection_thumbnail)));
|
let _res = tx.send(Some((path, display_thumbnail, selection_thumbnail)));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tx.send(None);
|
let _res = tx.send(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
rx.await.unwrap_or(None)
|
rx.await.unwrap_or(None)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue