mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 13:22:19 +01:00
refactor(bar-core): move ImageIcon, ImageIconId and the icons cache into the core
The icon cache (IconsCache, ICONS_CACHE, ImageIcon, ImageIconId, rgba_to_color_image) was in widgets/mod.rs of both bars with two small differences: Windows has `Hwnd(isize)`, `SystrayIcon(String)` and `remove`, macOS has `WindowId(u32)` and a private rgba_to_color_image. The core file is the Windows one with the macOS variant and `From<u32>` added (an enum with every variant, as D26 does for WidgetConfig); both bars re-export the items from widgets/mod.rs so no widget changes. The core gains the `image` dependency (one line in each Cargo.lock) and a Default impl for IconsCache (clippy). Verified: schema harness macOS and Windows byte-identical (3,774 / 9,091 lines); native bar-core tests 3+5; Windows clippy -D warnings --locked clean; macOS fake-CC check --locked 0 errors (re-run after touching the core files). Not run: the bars.
This commit is contained in:
1 parent
e7cf89d8f5
commit
0c197e8652
7 files changed
+194
-322
No files matched your search
Generated
+1
@@ -3447,6 +3447,7 @@ dependencies = [
|
||||
"chrono-tz",
|
||||
"eframe",
|
||||
"egui-phosphor",
|
||||
"image 0.25.10",
|
||||
"lazy_static",
|
||||
"reqwest",
|
||||
"schemars 1.2.3",
|
||||
|
||||
@@ -10,6 +10,7 @@ chrono-tz = { workspace = true }
|
||||
eframe = { workspace = true }
|
||||
egui-phosphor = { git = "https://github.com/amPerl/egui-phosphor", rev = "d13688738478ecd12b426e3e74c59d6577a85b59" }
|
||||
lazy_static = { workspace = true }
|
||||
image = "0.25"
|
||||
reqwest = { version = "0.12", features = ["blocking"] }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
use eframe::egui::ColorImage;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::TextureHandle;
|
||||
use eframe::egui::TextureOptions;
|
||||
use image::RgbaImage;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::RwLock;
|
||||
|
||||
/// Global cache for icon images and their associated GPU textures.
|
||||
pub static ICONS_CACHE: IconsCache = IconsCache::new();
|
||||
|
||||
/// In-memory cache for icon images and their associated GPU textures.
|
||||
///
|
||||
/// Stores raw [`ColorImage`]s and [`TextureHandle`]s keyed by [`ImageIconId`].
|
||||
/// Texture entries are context-dependent and automatically invalidated when the [`Context`] changes.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct IconsCache {
|
||||
textures: LazyLock<RwLock<(Option<Context>, HashMap<ImageIconId, TextureHandle>)>>,
|
||||
images: LazyLock<RwLock<HashMap<ImageIconId, Arc<ColorImage>>>>,
|
||||
}
|
||||
|
||||
impl IconsCache {
|
||||
/// Creates a new empty IconsCache instance.
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
textures: LazyLock::new(|| RwLock::new((None, HashMap::new()))),
|
||||
images: LazyLock::new(|| RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves or creates a texture handle for the given icon ID and image.
|
||||
///
|
||||
/// If a texture for the given ID already exists for the current [`Context`], it is reused.
|
||||
/// Otherwise, a new texture is created, inserted into the cache, and returned.
|
||||
/// The cache is reset if the [`Context`] has changed.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context, id: &ImageIconId, img: &Arc<ColorImage>) -> TextureHandle {
|
||||
if let Some(texture) = self.get_texture(ctx, id) {
|
||||
return texture;
|
||||
}
|
||||
let texture_handle = ctx.load_texture("icon", img.clone(), TextureOptions::default());
|
||||
self.insert_texture(ctx, id.clone(), texture_handle.clone());
|
||||
texture_handle
|
||||
}
|
||||
|
||||
/// Returns the cached texture for the given icon ID if it exists and matches the current [`Context`].
|
||||
pub fn get_texture(&self, ctx: &Context, id: &ImageIconId) -> Option<TextureHandle> {
|
||||
let textures_lock = self.textures.read().unwrap();
|
||||
if textures_lock.0.as_ref() == Some(ctx) {
|
||||
return textures_lock.1.get(id).cloned();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Inserts a texture handle, resetting the cache if the [`Context`] has changed.
|
||||
pub fn insert_texture(&self, ctx: &Context, id: ImageIconId, texture: TextureHandle) {
|
||||
let mut textures_lock = self.textures.write().unwrap();
|
||||
|
||||
if textures_lock.0.as_ref() != Some(ctx) {
|
||||
textures_lock.0 = Some(ctx.clone());
|
||||
textures_lock.1.clear();
|
||||
}
|
||||
|
||||
textures_lock.1.insert(id, texture);
|
||||
}
|
||||
|
||||
/// Returns the cached image for the given icon ID, if available.
|
||||
pub fn get_image(&self, id: &ImageIconId) -> Option<Arc<ColorImage>> {
|
||||
self.images.read().unwrap().get(id).cloned()
|
||||
}
|
||||
|
||||
/// Caches a raw [`ColorImage`] associated with the given icon ID.
|
||||
pub fn insert_image(&self, id: ImageIconId, image: Arc<ColorImage>) {
|
||||
self.images.write().unwrap().insert(id, image);
|
||||
}
|
||||
|
||||
/// Removes the cached image and texture for the given icon ID.
|
||||
pub fn remove(&self, id: &ImageIconId) {
|
||||
self.images.write().unwrap().remove(id);
|
||||
self.textures.write().unwrap().1.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rgba_to_color_image(rgba_image: &RgbaImage) -> ColorImage {
|
||||
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
||||
let pixels = rgba_image.as_flat_samples();
|
||||
ColorImage::from_rgba_unmultiplied(size, pixels.as_slice())
|
||||
}
|
||||
|
||||
/// Represents an image-based icon with a unique ID and pixel data.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageIcon {
|
||||
/// Unique identifier for the image icon, used for texture caching.
|
||||
pub id: ImageIconId,
|
||||
/// Shared pixel data of the icon in `ColorImage` format.
|
||||
pub image: Arc<ColorImage>,
|
||||
}
|
||||
|
||||
impl ImageIcon {
|
||||
/// Creates a new [`ImageIcon`] from the given ID and image data.
|
||||
#[inline]
|
||||
pub fn new(id: ImageIconId, image: Arc<ColorImage>) -> Self {
|
||||
Self { id, image }
|
||||
}
|
||||
|
||||
/// Loads an [`ImageIcon`] from [`ICONS_CACHE`] or calls `loader` if not cached.
|
||||
/// The loaded image is converted to a [`ColorImage`], cached, and returned.
|
||||
#[inline]
|
||||
pub fn try_load<F, I>(id: impl Into<ImageIconId>, loader: F) -> Option<Self>
|
||||
where
|
||||
F: FnOnce() -> Option<I>,
|
||||
I: Into<RgbaImage>,
|
||||
{
|
||||
let id = id.into();
|
||||
let image = ICONS_CACHE.get_image(&id).or_else(|| {
|
||||
let img = loader()?;
|
||||
let img = Arc::new(rgba_to_color_image(&img.into()));
|
||||
ICONS_CACHE.insert_image(id.clone(), img.clone());
|
||||
Some(img)
|
||||
})?;
|
||||
|
||||
Some(ImageIcon::new(id, image))
|
||||
}
|
||||
|
||||
/// Returns a texture handle for the icon, using the given [`Context`].
|
||||
///
|
||||
/// If the texture is already cached in [`ICONS_CACHE`], it is reused.
|
||||
/// Otherwise, a new texture is created from the [`ColorImage`] and cached.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context) -> TextureHandle {
|
||||
ICONS_CACHE.texture(ctx, &self.id, &self.image)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique identifier for an image-based icon.
|
||||
///
|
||||
/// Used to distinguish cached images and textures by either a file path
|
||||
/// or a Windows window handle.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ImageIconId {
|
||||
/// Identifier based on a file system path.
|
||||
Path(Arc<Path>),
|
||||
/// Windows HWND handle.
|
||||
Hwnd(isize),
|
||||
/// System tray icon identifier.
|
||||
SystrayIcon(String),
|
||||
/// macOS window ID.
|
||||
WindowId(u32),
|
||||
}
|
||||
|
||||
impl From<&Path> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: &Path) -> Self {
|
||||
Self::Path(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: isize) -> Self {
|
||||
Self::Hwnd(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: u32) -> Self {
|
||||
Self::WindowId(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for IconsCache {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod battery;
|
||||
pub mod cpu;
|
||||
pub mod date;
|
||||
pub mod icons;
|
||||
pub mod memory;
|
||||
pub mod storage;
|
||||
pub mod time;
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
use eframe::egui::ColorImage;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::TextureHandle;
|
||||
use eframe::egui::TextureOptions;
|
||||
use image::RgbaImage;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub mod applications;
|
||||
pub use komorebi_bar_core::widgets::battery;
|
||||
@@ -26,158 +16,7 @@ pub use komorebi_bar_core::widgets::time;
|
||||
pub use komorebi_bar_core::widgets::update;
|
||||
pub mod widget;
|
||||
|
||||
/// Global cache for icon images and their associated GPU textures.
|
||||
pub static ICONS_CACHE: IconsCache = IconsCache::new();
|
||||
|
||||
/// In-memory cache for icon images and their associated GPU textures.
|
||||
///
|
||||
/// Stores raw [`ColorImage`]s and [`TextureHandle`]s keyed by [`ImageIconId`].
|
||||
/// Texture entries are context-dependent and automatically invalidated when the [`Context`] changes.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct IconsCache {
|
||||
textures: LazyLock<RwLock<(Option<Context>, HashMap<ImageIconId, TextureHandle>)>>,
|
||||
images: LazyLock<RwLock<HashMap<ImageIconId, Arc<ColorImage>>>>,
|
||||
}
|
||||
|
||||
impl IconsCache {
|
||||
/// Creates a new empty IconsCache instance.
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
textures: LazyLock::new(|| RwLock::new((None, HashMap::new()))),
|
||||
images: LazyLock::new(|| RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves or creates a texture handle for the given icon ID and image.
|
||||
///
|
||||
/// If a texture for the given ID already exists for the current [`Context`], it is reused.
|
||||
/// Otherwise, a new texture is created, inserted into the cache, and returned.
|
||||
/// The cache is reset if the [`Context`] has changed.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context, id: &ImageIconId, img: &Arc<ColorImage>) -> TextureHandle {
|
||||
if let Some(texture) = self.get_texture(ctx, id) {
|
||||
return texture;
|
||||
}
|
||||
let texture_handle = ctx.load_texture("icon", img.clone(), TextureOptions::default());
|
||||
self.insert_texture(ctx, id.clone(), texture_handle.clone());
|
||||
texture_handle
|
||||
}
|
||||
|
||||
/// Returns the cached texture for the given icon ID if it exists and matches the current [`Context`].
|
||||
pub fn get_texture(&self, ctx: &Context, id: &ImageIconId) -> Option<TextureHandle> {
|
||||
let textures_lock = self.textures.read().unwrap();
|
||||
if textures_lock.0.as_ref() == Some(ctx) {
|
||||
return textures_lock.1.get(id).cloned();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Inserts a texture handle, resetting the cache if the [`Context`] has changed.
|
||||
pub fn insert_texture(&self, ctx: &Context, id: ImageIconId, texture: TextureHandle) {
|
||||
let mut textures_lock = self.textures.write().unwrap();
|
||||
|
||||
if textures_lock.0.as_ref() != Some(ctx) {
|
||||
textures_lock.0 = Some(ctx.clone());
|
||||
textures_lock.1.clear();
|
||||
}
|
||||
|
||||
textures_lock.1.insert(id, texture);
|
||||
}
|
||||
|
||||
/// Returns the cached image for the given icon ID, if available.
|
||||
pub fn get_image(&self, id: &ImageIconId) -> Option<Arc<ColorImage>> {
|
||||
self.images.read().unwrap().get(id).cloned()
|
||||
}
|
||||
|
||||
/// Caches a raw [`ColorImage`] associated with the given icon ID.
|
||||
pub fn insert_image(&self, id: ImageIconId, image: Arc<ColorImage>) {
|
||||
self.images.write().unwrap().insert(id, image);
|
||||
}
|
||||
|
||||
/// Removes the cached image and texture for the given icon ID.
|
||||
pub fn remove(&self, id: &ImageIconId) {
|
||||
self.images.write().unwrap().remove(id);
|
||||
self.textures.write().unwrap().1.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn rgba_to_color_image(rgba_image: &RgbaImage) -> ColorImage {
|
||||
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
||||
let pixels = rgba_image.as_flat_samples();
|
||||
ColorImage::from_rgba_unmultiplied(size, pixels.as_slice())
|
||||
}
|
||||
|
||||
/// Represents an image-based icon with a unique ID and pixel data.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageIcon {
|
||||
/// Unique identifier for the image icon, used for texture caching.
|
||||
pub id: ImageIconId,
|
||||
/// Shared pixel data of the icon in `ColorImage` format.
|
||||
pub image: Arc<ColorImage>,
|
||||
}
|
||||
|
||||
impl ImageIcon {
|
||||
/// Creates a new [`ImageIcon`] from the given ID and image data.
|
||||
#[inline]
|
||||
pub fn new(id: ImageIconId, image: Arc<ColorImage>) -> Self {
|
||||
Self { id, image }
|
||||
}
|
||||
|
||||
/// Loads an [`ImageIcon`] from [`ICONS_CACHE`] or calls `loader` if not cached.
|
||||
/// The loaded image is converted to a [`ColorImage`], cached, and returned.
|
||||
#[inline]
|
||||
pub fn try_load<F, I>(id: impl Into<ImageIconId>, loader: F) -> Option<Self>
|
||||
where
|
||||
F: FnOnce() -> Option<I>,
|
||||
I: Into<RgbaImage>,
|
||||
{
|
||||
let id = id.into();
|
||||
let image = ICONS_CACHE.get_image(&id).or_else(|| {
|
||||
let img = loader()?;
|
||||
let img = Arc::new(rgba_to_color_image(&img.into()));
|
||||
ICONS_CACHE.insert_image(id.clone(), img.clone());
|
||||
Some(img)
|
||||
})?;
|
||||
|
||||
Some(ImageIcon::new(id, image))
|
||||
}
|
||||
|
||||
/// Returns a texture handle for the icon, using the given [`Context`].
|
||||
///
|
||||
/// If the texture is already cached in [`ICONS_CACHE`], it is reused.
|
||||
/// Otherwise, a new texture is created from the [`ColorImage`] and cached.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context) -> TextureHandle {
|
||||
ICONS_CACHE.texture(ctx, &self.id, &self.image)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique identifier for an image-based icon.
|
||||
///
|
||||
/// Used to distinguish cached images and textures by either a file path
|
||||
/// or a Windows window handle.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ImageIconId {
|
||||
/// Identifier based on a file system path.
|
||||
Path(Arc<Path>),
|
||||
/// Windows HWND handle.
|
||||
Hwnd(isize),
|
||||
/// System tray icon identifier.
|
||||
SystrayIcon(String),
|
||||
}
|
||||
|
||||
impl From<&Path> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: &Path) -> Self {
|
||||
Self::Path(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: isize) -> Self {
|
||||
Self::Hwnd(value)
|
||||
}
|
||||
}
|
||||
pub use komorebi_bar_core::widgets::icons::ICONS_CACHE;
|
||||
pub use komorebi_bar_core::widgets::icons::ImageIcon;
|
||||
pub use komorebi_bar_core::widgets::icons::ImageIconId;
|
||||
pub use komorebi_bar_core::widgets::icons::rgba_to_color_image;
|
||||
Generated
+1
@@ -3255,6 +3255,7 @@ dependencies = [
|
||||
"chrono-tz",
|
||||
"eframe",
|
||||
"egui-phosphor",
|
||||
"image 0.25.10",
|
||||
"lazy_static",
|
||||
"reqwest",
|
||||
"schemars 1.2.3",
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
use eframe::egui::ColorImage;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::TextureHandle;
|
||||
use eframe::egui::TextureOptions;
|
||||
use image::RgbaImage;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub mod applications;
|
||||
pub use komorebi_bar_core::widgets::battery;
|
||||
@@ -22,150 +12,8 @@ pub use komorebi_bar_core::widgets::time;
|
||||
pub use komorebi_bar_core::widgets::update;
|
||||
pub mod widget;
|
||||
|
||||
/// Global cache for icon images and their associated GPU textures.
|
||||
pub static ICONS_CACHE: IconsCache = IconsCache::new();
|
||||
|
||||
/// In-memory cache for icon images and their associated GPU textures.
|
||||
///
|
||||
/// Stores raw [`ColorImage`]s and [`TextureHandle`]s keyed by [`ImageIconId`].
|
||||
/// Texture entries are context-dependent and automatically invalidated when the [`Context`] changes.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct IconsCache {
|
||||
textures: LazyLock<RwLock<(Option<Context>, HashMap<ImageIconId, TextureHandle>)>>,
|
||||
images: LazyLock<RwLock<HashMap<ImageIconId, Arc<ColorImage>>>>,
|
||||
}
|
||||
|
||||
impl IconsCache {
|
||||
/// Creates a new empty IconsCache instance.
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
textures: LazyLock::new(|| RwLock::new((None, HashMap::new()))),
|
||||
images: LazyLock::new(|| RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves or creates a texture handle for the given icon ID and image.
|
||||
///
|
||||
/// If a texture for the given ID already exists for the current [`Context`], it is reused.
|
||||
/// Otherwise, a new texture is created, inserted into the cache, and returned.
|
||||
/// The cache is reset if the [`Context`] has changed.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context, id: &ImageIconId, img: &Arc<ColorImage>) -> TextureHandle {
|
||||
if let Some(texture) = self.get_texture(ctx, id) {
|
||||
return texture;
|
||||
}
|
||||
let texture_handle = ctx.load_texture("icon", img.clone(), TextureOptions::default());
|
||||
self.insert_texture(ctx, id.clone(), texture_handle.clone());
|
||||
texture_handle
|
||||
}
|
||||
|
||||
/// Returns the cached texture for the given icon ID if it exists and matches the current [`Context`].
|
||||
pub fn get_texture(&self, ctx: &Context, id: &ImageIconId) -> Option<TextureHandle> {
|
||||
let textures_lock = self.textures.read().unwrap();
|
||||
if textures_lock.0.as_ref() == Some(ctx) {
|
||||
return textures_lock.1.get(id).cloned();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Inserts a texture handle, resetting the cache if the [`Context`] has changed.
|
||||
pub fn insert_texture(&self, ctx: &Context, id: ImageIconId, texture: TextureHandle) {
|
||||
let mut textures_lock = self.textures.write().unwrap();
|
||||
|
||||
if textures_lock.0.as_ref() != Some(ctx) {
|
||||
textures_lock.0 = Some(ctx.clone());
|
||||
textures_lock.1.clear();
|
||||
}
|
||||
|
||||
textures_lock.1.insert(id, texture);
|
||||
}
|
||||
|
||||
/// Returns the cached image for the given icon ID, if available.
|
||||
pub fn get_image(&self, id: &ImageIconId) -> Option<Arc<ColorImage>> {
|
||||
self.images.read().unwrap().get(id).cloned()
|
||||
}
|
||||
|
||||
/// Caches a raw [`ColorImage`] associated with the given icon ID.
|
||||
pub fn insert_image(&self, id: ImageIconId, image: Arc<ColorImage>) {
|
||||
self.images.write().unwrap().insert(id, image);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rgba_to_color_image(rgba_image: &RgbaImage) -> ColorImage {
|
||||
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
||||
let pixels = rgba_image.as_flat_samples();
|
||||
ColorImage::from_rgba_unmultiplied(size, pixels.as_slice())
|
||||
}
|
||||
|
||||
/// Represents an image-based icon with a unique ID and pixel data.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageIcon {
|
||||
/// Unique identifier for the image icon, used for texture caching.
|
||||
pub id: ImageIconId,
|
||||
/// Shared pixel data of the icon in `ColorImage` format.
|
||||
pub image: Arc<ColorImage>,
|
||||
}
|
||||
|
||||
impl ImageIcon {
|
||||
/// Creates a new [`ImageIcon`] from the given ID and image data.
|
||||
#[inline]
|
||||
pub fn new(id: ImageIconId, image: Arc<ColorImage>) -> Self {
|
||||
Self { id, image }
|
||||
}
|
||||
|
||||
/// Loads an [`ImageIcon`] from [`ICONS_CACHE`] or calls `loader` if not cached.
|
||||
/// The loaded image is converted to a [`ColorImage`], cached, and returned.
|
||||
#[inline]
|
||||
pub fn try_load<F, I>(id: impl Into<ImageIconId>, loader: F) -> Option<Self>
|
||||
where
|
||||
F: FnOnce() -> Option<I>,
|
||||
I: Into<RgbaImage>,
|
||||
{
|
||||
let id = id.into();
|
||||
let image = ICONS_CACHE.get_image(&id).or_else(|| {
|
||||
let img = loader()?;
|
||||
let img = Arc::new(rgba_to_color_image(&img.into()));
|
||||
ICONS_CACHE.insert_image(id.clone(), img.clone());
|
||||
Some(img)
|
||||
})?;
|
||||
|
||||
Some(ImageIcon::new(id, image))
|
||||
}
|
||||
|
||||
/// Returns a texture handle for the icon, using the given [`Context`].
|
||||
///
|
||||
/// If the texture is already cached in [`ICONS_CACHE`], it is reused.
|
||||
/// Otherwise, a new texture is created from the [`ColorImage`] and cached.
|
||||
#[inline]
|
||||
pub fn texture(&self, ctx: &Context) -> TextureHandle {
|
||||
ICONS_CACHE.texture(ctx, &self.id, &self.image)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique identifier for an image-based icon.
|
||||
///
|
||||
/// Used to distinguish cached images and textures by either a file path
|
||||
/// or a Windows window handle.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ImageIconId {
|
||||
/// Identifier based on a file system path.
|
||||
Path(Arc<Path>),
|
||||
/// Window ID
|
||||
WindowId(u32),
|
||||
}
|
||||
|
||||
impl From<&Path> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: &Path) -> Self {
|
||||
Self::Path(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ImageIconId {
|
||||
#[inline]
|
||||
fn from(value: u32) -> Self {
|
||||
Self::WindowId(value)
|
||||
}
|
||||
}
|
||||
pub use komorebi_bar_core::widgets::icons::ICONS_CACHE;
|
||||
pub use komorebi_bar_core::widgets::icons::ImageIcon;
|
||||
pub use komorebi_bar_core::widgets::icons::ImageIconId;
|
||||
#[allow(unused_imports)]
|
||||
pub use komorebi_bar_core::widgets::icons::rgba_to_color_image;
|
||||
Reference in new issue
Block a user