feat(icon): optimize & bundle icons with crabtime for non-unix platforms
3
.gitmodules
vendored
|
|
@ -2,3 +2,6 @@
|
|||
path = iced
|
||||
url = https://github.com/pop-os/iced.git
|
||||
branch = master
|
||||
[submodule "icon-theme"]
|
||||
path = cosmic-icons
|
||||
url = https://github.com/pop-os/cosmic-icons
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-c
|
|||
chrono = "0.4.42"
|
||||
cosmic-config = { path = "cosmic-config" }
|
||||
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true }
|
||||
# Compile-time generation of code
|
||||
crabtime = "1.1.4"
|
||||
# Internationalization
|
||||
i18n-embed = { version = "0.16.0", features = [
|
||||
"fluent-system",
|
||||
|
|
@ -152,6 +154,10 @@ freedesktop-icons = { package = "cosmic-freedesktop-icons", git = "https://githu
|
|||
freedesktop-desktop-entry = { version = "0.7.14", optional = true }
|
||||
shlex = { version = "1.3.0", optional = true }
|
||||
|
||||
[target.'cfg(not(unix))'.dependencies]
|
||||
# Used to embed bundled icons for non-unix platforms.
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
|
||||
[dependencies.cosmic-theme]
|
||||
path = "cosmic-theme"
|
||||
|
||||
|
|
@ -222,4 +228,3 @@ dirs = "6.0.0"
|
|||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.13.0"
|
||||
|
||||
|
|
|
|||
1
cosmic-icons
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 70b07582e24ec2114672256b9657ca80670bca8a
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 4C10 3.446 9.554 3 9 3H4C3.446 3 3 3.446 3 4C3 4.554 3.446 5 4 5H9C9.554 5 10 4.554 10 4ZM7 8C7 7.446 6.554 7 6 7H4C3.446 7 3 7.446 3 8C3 8.554 3.446 9 4 9H6C6.554 9 7 8.554 7 8ZM10 12C10 11.446 9.554 11 9 11H4C3.446 11 3 11.446 3 12C3 12.554 3.446 13 4 13H9C9.554 13 10 12.554 10 12Z" fill="#232323"/>
|
||||
<path d="M12 5L9 8L12 11" stroke="#232323" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 528 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.8 8.61106C11.8 8.61106 12 8.37437 12 8.01163C12 7.64889 11.8 7.4122 11.8 7.4122L5.59947 1.21812C5.59947 1.21812 4.86007 0.63914 4.24935 1.36778C3.71912 1.96029 4.19936 2.61659 4.19936 2.61659L9.49979 8.01163L4.19936 13.4063C4.19936 13.4063 3.71913 14.0057 4.24936 14.6551C4.8405 15.3309 5.59947 14.8051 5.59947 14.8051L11.8 8.61106Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 467 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.20002 8.61106C4.20002 8.61106 4.00002 8.37437 4 8.01163C3.99998 7.64889 4.20002 7.4122 4.20002 7.4122L10.4005 1.21812C10.4005 1.21812 11.1399 0.63914 11.7507 1.36778C12.2809 1.96029 11.8006 2.61659 11.8006 2.61659L6.50021 8.01163L11.8006 13.4063C11.8006 13.4063 12.2809 14.0057 11.7506 14.6551C11.1595 15.3309 10.4005 14.8051 10.4005 14.8051L4.20002 8.61106Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 492 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3C7.73478 3 7.48043 3.10536 7.29289 3.29289C7.10536 3.48043 7 3.73478 7 4V6.996L4 7C3.73478 7 3.48043 7.10536 3.29289 7.29289C3.10536 7.48043 3 7.73478 3 8C3 8.26522 3.10536 8.51957 3.29289 8.70711C3.48043 8.89464 3.73478 9 4 9L7 8.996V12C7 12.2652 7.10536 12.5196 7.29289 12.7071C7.48043 12.8946 7.73478 13 8 13C8.26522 13 8.51957 12.8946 8.70711 12.7071C8.89464 12.5196 9 12.2652 9 12V8.996L12 9C12.2652 9 12.5196 8.89464 12.7071 8.70711C12.8946 8.51957 13 8.26522 13 8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7L9 6.996V4C9 3.73478 8.89464 3.48043 8.70711 3.29289C8.51957 3.10536 8.26522 3 8 3Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 762 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 7C3.73478 7 3.48043 7.10536 3.29289 7.29289C3.10536 7.48043 3 7.73478 3 8C3 8.26522 3.10536 8.51957 3.29289 8.70711C3.48043 8.89464 3.73478 9 4 9H12C12.2652 9 12.5196 8.89464 12.7071 8.70711C12.8946 8.51957 13 8.26522 13 8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7H4Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 433 B |
|
|
@ -1,10 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_3277_252" fill="white">
|
||||
<rect x="1" y="2" width="14" height="12" rx="1"/>
|
||||
</mask>
|
||||
<rect x="1" y="2" width="14" height="12" rx="1" stroke="#232323" stroke-width="4" mask="url(#path-1-inside-1_3277_252)"/>
|
||||
<rect x="6" y="2" width="2" height="12" fill="#232323"/>
|
||||
<rect x="4" y="5" width="1" height="1" fill="#232323"/>
|
||||
<rect x="4" y="7" width="1" height="1" fill="#232323"/>
|
||||
<rect x="4" y="9" width="1" height="1" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 558 B |
|
|
@ -1,8 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_3277_253" fill="white">
|
||||
<rect x="1" y="2" width="14" height="12" rx="1"/>
|
||||
</mask>
|
||||
<rect x="1" y="2" width="14" height="12" rx="1" stroke="#232323" stroke-width="4" mask="url(#path-1-inside-1_3277_253)"/>
|
||||
<rect x="5" y="2" width="2" height="12" fill="#232323"/>
|
||||
<path d="M7.99983 8.02603L10.9998 5C10.9998 5 11.5568 4.55672 12 5.00002C12.4432 5.44331 12 6.00002 12 6.00002L10 8.02603L12 10C12 10 12.5 10.5 12 11C11.5 11.5 11 11 11 11L7.99983 8.02603Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 597 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 4C13 3.446 12.554 3 12 3H4C3.446 3 3 3.446 3 4C3 4.554 3.446 5 4 5H12C12.554 5 13 4.554 13 4ZM13 8C13 7.446 12.554 7 12 7H4C3.446 7 3 7.446 3 8C3 8.554 3.446 9 4 9H12C12.554 9 13 8.554 13 8ZM13 12C13 11.446 12.554 11 12 11H4C3.446 11 3 11.446 3 12C3 12.554 3.446 13 4 13H12C12.554 13 13 12.554 13 12Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 435 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 4.00299C4.73478 4.00299 4.48043 4.10835 4.29289 4.29588C4.10536 4.48342 4 4.73777 4 5.00299C4.00006 5.26819 4.10545 5.5225 4.293 5.70999L6.586 8.00299L4.293 10.296C4.10545 10.4835 4.00006 10.7378 4 11.003C4 11.2682 4.10536 11.5226 4.29289 11.7101C4.48043 11.8976 4.73478 12.003 5 12.003C5.26519 12.0029 5.51951 11.8975 5.707 11.71L8 9.41699L10.283 11.7C10.3762 11.7959 10.4877 11.8721 10.6108 11.9241C10.734 11.9762 10.8663 12.003 11 12.003C11.2652 12.003 11.5196 11.8976 11.7071 11.7101C11.8946 11.5226 12 11.2682 12 11.003C11.9999 10.7378 11.8945 10.4835 11.707 10.296L9.414 8.00299L11.697 5.71999C11.7929 5.6268 11.8691 5.51534 11.9211 5.39218C11.9732 5.26903 12 5.13669 12 5.00299C12 4.73777 11.8946 4.48342 11.7071 4.29588C11.5196 4.10835 11.2652 4.00299 11 4.00299C10.7348 4.00305 10.4805 4.10844 10.293 4.29599L8 6.58899L5.717 4.30599C5.71369 4.30263 5.71036 4.2993 5.707 4.29599C5.51951 4.10844 5.26519 4.00305 5 4.00299Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1 KiB |
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 12H8L6.5 10.5L7.78947 9.15789C7.78947 9.15789 8.26316 8.68421 7.78947 8.21053C7.31579 7.73684 6.8421 8.21053 6.8421 8.21053L5.5 9.5L4 8V12Z" fill="#232323"/>
|
||||
<path d="M12 4H8L9.5 5.5L8.21053 6.84211C8.21053 6.84211 7.73684 7.31579 8.21053 7.78947C8.68421 8.26316 9.1579 7.78947 9.1579 7.78947L10.5 6.5L12 8V4Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 443 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 10V12H12V10H4Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 188 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 8H4L5.5 9.5L4.21053 10.8421C4.21053 10.8421 3.73684 11.3158 4.21053 11.7895C4.68421 12.2632 5.1579 11.7895 5.1579 11.7895L6.5 10.5L8 12V8Z" fill="#232323"/>
|
||||
<path d="M8 8H12L10.5 6.5L11.7895 5.15789C11.7895 5.15789 12.2632 4.68421 11.7895 4.21053C11.3158 3.73684 10.8421 4.21053 10.8421 4.21053L9.5 5.5L8 4V8Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 443 B |
|
|
@ -132,10 +132,6 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
|||
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
|
||||
let mut content = Vec::with_capacity(2);
|
||||
|
||||
if let icon::Data::Name(ref mut named) = builder.variant.handle.data {
|
||||
named.size = Some(builder.icon_size);
|
||||
}
|
||||
|
||||
content.push(
|
||||
crate::widget::icon(builder.variant.handle.clone())
|
||||
.size(builder.icon_size)
|
||||
|
|
|
|||
|
|
@ -91,21 +91,15 @@ impl<Message> Button<'_, Message> {
|
|||
|
||||
impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
|
||||
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
|
||||
let trailing_icon = builder.variant.trailing_icon.map(|mut i| {
|
||||
if let icon::Data::Name(ref mut named) = i.data {
|
||||
named.size = Some(builder.icon_size);
|
||||
}
|
||||
let trailing_icon = builder
|
||||
.variant
|
||||
.trailing_icon
|
||||
.map(crate::widget::icon::Handle::icon);
|
||||
|
||||
i.icon()
|
||||
});
|
||||
|
||||
let leading_icon = builder.variant.leading_icon.map(|mut i| {
|
||||
if let icon::Data::Name(ref mut named) = i.data {
|
||||
named.size = Some(builder.icon_size);
|
||||
}
|
||||
|
||||
i.icon()
|
||||
});
|
||||
let leading_icon = builder
|
||||
.variant
|
||||
.leading_icon
|
||||
.map(crate::widget::icon::Handle::icon);
|
||||
|
||||
let label: Option<Element<'_, _>> = (!builder.label.is_empty()).then(|| {
|
||||
let font = crate::font::Font {
|
||||
|
|
|
|||
|
|
@ -230,10 +230,6 @@ impl<Item: Clone + PartialEq + 'static> State<Item> {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
icon: match icon::from_name("pan-down-symbolic").size(16).handle().data {
|
||||
icon::Data::Name(named) => named
|
||||
.path()
|
||||
.filter(|path| path.extension().is_some_and(|ext| ext == OsStr::new("svg")))
|
||||
.map(iced_core::svg::Handle::from_path),
|
||||
icon::Data::Svg(handle) => Some(handle),
|
||||
icon::Data::Image(_) => None,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -407,10 +407,6 @@ impl State {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
icon: match icon::from_name("pan-down-symbolic").size(16).handle().data {
|
||||
icon::Data::Name(named) => named
|
||||
.path()
|
||||
.filter(|path| path.extension().is_some_and(|ext| ext == OsStr::new("svg")))
|
||||
.map(iced_core::svg::Handle::from_path),
|
||||
icon::Data::Svg(handle) => Some(handle),
|
||||
icon::Data::Image(_) => None,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -449,25 +449,12 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
|||
fn window_controls(&mut self) -> Element<'a, Message> {
|
||||
macro_rules! icon {
|
||||
($name:expr, $size:expr, $on_press:expr) => {{
|
||||
#[cfg(target_os = "linux")]
|
||||
let icon = {
|
||||
widget::icon::from_name($name)
|
||||
.apply(widget::button::icon)
|
||||
.padding(8)
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let icon = {
|
||||
widget::icon::from_svg_bytes(include_bytes!(concat!(
|
||||
"../../res/icons/",
|
||||
$name,
|
||||
".svg"
|
||||
)))
|
||||
.symbolic(true)
|
||||
.apply(widget::button::icon)
|
||||
.padding(8)
|
||||
};
|
||||
|
||||
icon.class(crate::theme::Button::HeaderBar)
|
||||
.selected(self.focused)
|
||||
.icon_size($size)
|
||||
|
|
|
|||
62
src/widget/icon/bundle.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2025 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Embedded icons for platforms which do not support icon themes yet.
|
||||
|
||||
/// Icon bundling is not enabled on unix platforms.
|
||||
pub fn get(icon_name: &str) -> Option<super::Data> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
/// Get a bundled icon on non-unix platforms.
|
||||
pub fn get(icon_name: &str) -> Option<super::Data> {
|
||||
ICONS
|
||||
.get(icon_name)
|
||||
.map(|bytes| super::Data::Svg(crate::iced::widget::svg::Handle::from_memory(*bytes)))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[crabtime::expression]
|
||||
fn comptime_icon_bundler() -> String {
|
||||
let manifest_dir = std::path::Path::new(crabtime::WORKSPACE_PATH);
|
||||
let icon_paths = [
|
||||
"cosmic-icons/freedesktop/scalable",
|
||||
"cosmic-icons/extra/scalable",
|
||||
];
|
||||
|
||||
let key_value_assignments = icon_paths
|
||||
.into_iter()
|
||||
.map(|path| manifest_dir.join(path))
|
||||
.inspect(|icon_path| assert!(icon_path.exists(), "path = {icon_path:?}"))
|
||||
.map(|icon_path| std::fs::read_dir(icon_path).unwrap())
|
||||
.flat_map(|dir| {
|
||||
dir.flat_map(|entry| entry.unwrap().path().read_dir().unwrap())
|
||||
.map(|entry| {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path().canonicalize().unwrap();
|
||||
let file_name = path.file_stem().unwrap().to_str().unwrap().to_owned();
|
||||
let path = path.into_os_string().into_string().unwrap();
|
||||
(file_name, path)
|
||||
})
|
||||
})
|
||||
.fold(
|
||||
std::collections::BTreeMap::new(),
|
||||
|mut set, (name, path)| {
|
||||
set.insert(name, path);
|
||||
set
|
||||
},
|
||||
)
|
||||
.into_iter()
|
||||
.fold(String::new(), |mut output, (name, path)| {
|
||||
output.push_str(&format!(" \"{name}\" => include_bytes!(\"{path}\"),\n"));
|
||||
output
|
||||
});
|
||||
|
||||
["phf::phf_map!(\n", &key_value_assignments, ")"].concat()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
static ICONS: phf::Map<&'static str, &'static [u8]> = {
|
||||
comptime_icon_bundler! {}
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{Icon, Named};
|
||||
use super::Icon;
|
||||
use crate::widget::{image, svg};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
|
|
@ -26,7 +26,7 @@ impl Handle {
|
|||
#[must_use]
|
||||
#[derive(Clone, Debug, Hash)]
|
||||
pub enum Data {
|
||||
Name(Named),
|
||||
// Name(Named),
|
||||
Image(image::Handle),
|
||||
Svg(svg::Handle),
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ pub fn from_raster_pixels(
|
|||
/// Create a SVG handle from memory.
|
||||
pub fn from_svg_bytes(bytes: impl Into<Cow<'static, [u8]>>) -> Handle {
|
||||
Handle {
|
||||
symbolic: false,
|
||||
symbolic: true,
|
||||
data: Data::Svg(svg::Handle::from_memory(bytes)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
//! Lazily-generated SVG icon widget for Iced.
|
||||
|
||||
mod bundle;
|
||||
mod named;
|
||||
use std::ffi::OsStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use named::{IconFallback, Named};
|
||||
|
|
@ -58,14 +58,6 @@ impl Icon {
|
|||
#[must_use]
|
||||
pub fn into_svg_handle(self) -> Option<crate::widget::svg::Handle> {
|
||||
match self.handle.data {
|
||||
Data::Name(named) => {
|
||||
if let Some(path) = named.path() {
|
||||
if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
return Some(iced_core::svg::Handle::from_path(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Data::Image(_) => (),
|
||||
Data::Svg(handle) => return Some(handle),
|
||||
}
|
||||
|
|
@ -76,12 +68,6 @@ impl Icon {
|
|||
#[must_use]
|
||||
pub fn size(mut self, size: u16) -> Self {
|
||||
self.size = size;
|
||||
// ensures correct icon size variant selection
|
||||
if let Data::Name(named) = &self.handle.data {
|
||||
let mut new_named = named.clone();
|
||||
new_named.size = Some(size);
|
||||
self.handle = new_named.handle();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -120,19 +106,6 @@ impl Icon {
|
|||
};
|
||||
|
||||
match self.handle.data {
|
||||
Data::Name(named) => {
|
||||
if let Some(path) = named.path() {
|
||||
if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
from_svg(iced_core::svg::Handle::from_path(path))
|
||||
} else {
|
||||
from_image(iced_core::image::Handle::from_path(path))
|
||||
}
|
||||
} else {
|
||||
let bytes: &'static [u8] = &[];
|
||||
from_svg(iced_core::svg::Handle::from_memory(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
Data::Image(handle) => from_image(handle),
|
||||
Data::Svg(handle) => from_svg(handle),
|
||||
}
|
||||
|
|
@ -147,32 +120,14 @@ impl<'a, Message: 'a> From<Icon> for Element<'a, Message> {
|
|||
|
||||
/// Draw an icon in the given bounds via the runtime's renderer.
|
||||
pub fn draw(renderer: &mut crate::Renderer, handle: &Handle, icon_bounds: Rectangle) {
|
||||
enum IcedHandle {
|
||||
Svg(iced_core::svg::Handle),
|
||||
Image(iced_core::image::Handle),
|
||||
}
|
||||
|
||||
let iced_handle = match handle.clone().data {
|
||||
Data::Name(named) => named.path().map(|path| {
|
||||
if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
IcedHandle::Svg(iced_core::svg::Handle::from_path(path))
|
||||
} else {
|
||||
IcedHandle::Image(iced_core::image::Handle::from_path(path))
|
||||
}
|
||||
}),
|
||||
|
||||
Data::Image(handle) => Some(IcedHandle::Image(handle)),
|
||||
Data::Svg(handle) => Some(IcedHandle::Svg(handle)),
|
||||
};
|
||||
|
||||
match iced_handle {
|
||||
Some(IcedHandle::Svg(handle)) => iced_core::svg::Renderer::draw_svg(
|
||||
match handle.clone().data {
|
||||
Data::Svg(handle) => iced_core::svg::Renderer::draw_svg(
|
||||
renderer,
|
||||
iced_core::svg::Svg::new(handle),
|
||||
icon_bounds,
|
||||
),
|
||||
|
||||
Some(IcedHandle::Image(handle)) => {
|
||||
Data::Image(handle) => {
|
||||
iced_core::image::Renderer::draw_image(
|
||||
renderer,
|
||||
handle,
|
||||
|
|
@ -183,7 +138,5 @@ pub fn draw(renderer: &mut crate::Renderer, handle: &Handle, icon_bounds: Rectan
|
|||
[0.0; 4],
|
||||
);
|
||||
}
|
||||
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{Handle, Icon};
|
||||
use std::{borrow::Cow, path::PathBuf, sync::Arc};
|
||||
use std::{borrow::Cow, ffi::OsStr, path::PathBuf, sync::Arc};
|
||||
|
||||
#[derive(Debug, Clone, Default, Hash)]
|
||||
/// Fallback icon to use if the icon was not found.
|
||||
|
|
@ -116,9 +116,21 @@ impl Named {
|
|||
|
||||
#[inline]
|
||||
pub fn handle(self) -> Handle {
|
||||
let name = self.name.clone();
|
||||
Handle {
|
||||
symbolic: self.symbolic,
|
||||
data: super::Data::Name(self),
|
||||
data: if let Some(path) = self.path() {
|
||||
if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
super::Data::Svg(iced_core::svg::Handle::from_path(path))
|
||||
} else {
|
||||
super::Data::Image(iced_core::image::Handle::from_path(path))
|
||||
}
|
||||
} else {
|
||||
super::bundle::get(&name).unwrap_or_else(|| {
|
||||
let bytes: &'static [u8] = &[];
|
||||
super::Data::Svg(iced_core::svg::Handle::from_memory(bytes))
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,18 +28,12 @@ pub const fn nav_bar_toggle<Message>() -> NavBarToggle<Message> {
|
|||
impl<Message: 'static + Clone> From<NavBarToggle<Message>> for Element<'_, Message> {
|
||||
fn from(nav_bar_toggle: NavBarToggle<Message>) -> Self {
|
||||
let icon = if nav_bar_toggle.active {
|
||||
widget::icon::from_svg_bytes(
|
||||
&include_bytes!("../../res/icons/navbar-open-symbolic.svg")[..],
|
||||
)
|
||||
.symbolic(true)
|
||||
"navbar-open-symbolic"
|
||||
} else {
|
||||
widget::icon::from_svg_bytes(
|
||||
&include_bytes!("../../res/icons/navbar-closed-symbolic.svg")[..],
|
||||
)
|
||||
.symbolic(true)
|
||||
"navbar-closed-symbolic"
|
||||
};
|
||||
|
||||
widget::button::icon(icon)
|
||||
widget::button::icon(widget::icon::from_name(icon))
|
||||
.padding([8, 16])
|
||||
.on_press_maybe(nav_bar_toggle.on_toggle)
|
||||
.selected(nav_bar_toggle.selected)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn increment<T>(value: T, step: T, min: T, max: T) -> T
|
||||
fn increment<T>(value: T, step: T, _min: T, max: T) -> T
|
||||
where
|
||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||
{
|
||||
|
|
@ -126,7 +126,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn decrement<T>(value: T, step: T, min: T, max: T) -> T
|
||||
fn decrement<T>(value: T, step: T, min: T, _max: T) -> T
|
||||
where
|
||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||
{
|
||||
|
|
@ -149,25 +149,25 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
macro_rules! make_button {
|
||||
($spin_button:expr, $icon:expr, $operation:expr) => {{
|
||||
#[cfg(target_os = "linux")]
|
||||
let button = icon::from_name($icon);
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let button =
|
||||
icon::from_svg_bytes(include_bytes!(concat!["../../res/icons/", $icon, ".svg"]))
|
||||
.symbolic(true);
|
||||
|
||||
button
|
||||
.apply(button::icon)
|
||||
.on_press(($spin_button.on_press)($operation(
|
||||
$spin_button.value,
|
||||
$spin_button.step,
|
||||
$spin_button.min,
|
||||
$spin_button.max,
|
||||
)))
|
||||
}};
|
||||
fn make_button<'a, T, Message>(
|
||||
spin_button: &SpinButton<'a, T, Message>,
|
||||
icon: &'static str,
|
||||
operation: fn(T, T, T, T) -> T,
|
||||
) -> Element<'a, Message>
|
||||
where
|
||||
Message: Clone + 'static,
|
||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||
{
|
||||
icon::from_name(icon)
|
||||
.apply(button::icon)
|
||||
.on_press((spin_button.on_press)(operation(
|
||||
spin_button.value,
|
||||
spin_button.step,
|
||||
spin_button.min,
|
||||
spin_button.max,
|
||||
)))
|
||||
.into()
|
||||
}
|
||||
|
||||
fn horizontal_variant<T, Message>(spin_button: SpinButton<'_, T, Message>) -> Element<'_, Message>
|
||||
|
|
@ -175,8 +175,8 @@ where
|
|||
Message: Clone + 'static,
|
||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||
{
|
||||
let decrement_button = make_button!(spin_button, "list-remove-symbolic", decrement);
|
||||
let increment_button = make_button!(spin_button, "list-add-symbolic", increment);
|
||||
let decrement_button = make_button(&spin_button, "list-remove-symbolic", decrement);
|
||||
let increment_button = make_button(&spin_button, "list-add-symbolic", increment);
|
||||
|
||||
let label = text::body(spin_button.label)
|
||||
.apply(container)
|
||||
|
|
@ -198,8 +198,8 @@ where
|
|||
Message: Clone + 'static,
|
||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||
{
|
||||
let decrement_button = make_button!(spin_button, "list-remove-symbolic", decrement);
|
||||
let increment_button = make_button!(spin_button, "list-add-symbolic", increment);
|
||||
let decrement_button = make_button(&spin_button, "list-remove-symbolic", decrement);
|
||||
let increment_button = make_button(&spin_button, "list-add-symbolic", increment);
|
||||
|
||||
let label = text::body(spin_button.label)
|
||||
.apply(container)
|
||||
|
|
|
|||
|
|
@ -33,20 +33,11 @@ impl<'a, Message: 'static + Clone> Warning<'a, Message> {
|
|||
pub fn into_widget(self) -> widget::Container<'a, Message, crate::Theme, Renderer> {
|
||||
let label = widget::container(crate::widget::text(self.message)).width(Length::Fill);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let close_button = icon::from_name("window-close-symbolic")
|
||||
.size(16)
|
||||
.apply(widget::button::icon)
|
||||
.on_press_maybe(self.on_close);
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let close_button =
|
||||
icon::from_svg_bytes(include_bytes!("../../res/icons/window-close-symbolic.svg"))
|
||||
.symbolic(true)
|
||||
.apply(widget::button::icon)
|
||||
.icon_size(16)
|
||||
.on_press_maybe(self.on_close);
|
||||
|
||||
widget::row::with_capacity(2)
|
||||
.push(label)
|
||||
.push(close_button)
|
||||
|
|
|
|||