use std::collections::HashMap;
use crate::{prelude::*, render_helper::RenderProxy};
#[derive(Clone)]
pub struct IconTheme {
pub icon_size: IconSize,
svgs: HashMap<NamedSvg, Resource<Svg>, ahash::RandomState>,
}
#[derive(Debug, Clone)]
pub struct IconSize {
pub tiny: Size,
pub small: Size,
pub medium: Size,
pub large: Size,
pub huge: Size,
}
pub const MISS_ICON: NamedSvg = NamedSvg(0);
pub const BEGIN: NamedSvg = NamedSvg::new(1);
#[macro_export]
macro_rules! define_named_svg {
($from: expr, $define: ident, $($ident: ident),+) => {
define_named_svg!($from, $define);
define_named_svg!(NamedSvg($define.0 + 1), $($ident), +);
};
($value: expr, $define: ident) => {
pub const $define: NamedSvg = $value;
}
}
#[macro_export]
macro_rules! fill_svgs {
($theme: expr, $($name: path: $path: literal),+) => {
$(
let icon = Resource::new(include_crate_svg!($path, true, false));
$theme.set_svg($name, icon);
)+
};
}
pub const CUSTOM_ICON_START: NamedSvg = NamedSvg::new(65536);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct NamedSvg(pub usize);
impl Compose for NamedSvg {
fn compose(this: impl StateWriter<Value = Self>) -> Widget<'static> {
pipe!(*$read(this))
.map(|v| v.of_or_miss(BuildCtx::get()))
.into_widget()
}
}
impl IconTheme {
pub fn new(icon_size: IconSize) -> Self {
let svg = include_crate_svg!("src/builtin_widgets/default_named.svg", true, false);
let miss_icon = Resource::new(svg);
let mut icons = HashMap::<_, _, ahash::RandomState>::default();
icons.insert(MISS_ICON, miss_icon);
Self { icon_size, svgs: icons }
}
#[inline]
pub fn of(ctx: &impl AsRef<ProviderCtx>) -> QueryRef<'_, Self> {
Provider::of::<Self>(ctx).unwrap()
}
#[inline]
pub fn write_of(ctx: &impl AsRef<ProviderCtx>) -> WriteRef<'_, Self> {
Provider::write_of::<Self>(ctx).unwrap()
}
#[inline]
pub fn set_svg(&mut self, name: NamedSvg, icon: Resource<Svg>) -> Option<Resource<Svg>> {
self.svgs.insert(name, icon)
}
#[inline]
pub fn has_svg(&mut self, name: &NamedSvg) -> bool { self.svgs.contains_key(name) }
}
impl IconSize {
pub fn of(ctx: &impl AsRef<ProviderCtx>) -> QueryRef<'_, Self> {
QueryRef::map(IconTheme::of(ctx), |i| &i.icon_size)
}
}
impl NamedSvg {
pub const fn new(idx: usize) -> Self { Self(idx) }
pub fn of_or_miss(self, ctx: &impl AsRef<ProviderCtx>) -> Resource<Svg> {
NamedSvg::of(self, ctx)
.or_else(|| MISS_ICON.of(ctx))
.expect("Neither Icon({:?}) nor 'MISS_ICON' are initialized in all `IconTheme` instances.")
}
pub fn of(self, ctx: &impl AsRef<ProviderCtx>) -> Option<Resource<Svg>> {
IconTheme::of(ctx).svgs.get(&self).cloned()
}
}
pub mod svgs {
use super::*;
define_named_svg!(
BEGIN,
ADD,
ARROW_BACK,
ARROW_DROP_DOWN,
ARROW_FORWARD,
CANCEL,
CHECK_BOX,
CHECK_BOX_OUTLINE_BLANK,
CHEVRON_RIGHT,
CLOSE,
DELETE,
DONE,
EXPAND_MORE,
FAVORITE,
HOME,
INDETERMINATE_CHECK_BOX,
LOGIN,
LOGOUT,
MENU,
MORE_HORIZ,
MORE_VERT,
OPEN_IN_NEW,
SEARCH,
SETTINGS,
STAR,
TEXT_CARET,
THEME_EXTEND
);
}
impl RenderProxy for Resource<Svg> {
fn proxy(&self) -> impl Deref<Target = impl Render + ?Sized> { &**self }
}