296 lines
16 KiB
Rust
296 lines
16 KiB
Rust
use iced_widget::image::Handle;
|
|
use include_dir::{Dir, include_dir};
|
|
use resvg::tiny_skia;
|
|
use std::collections::HashMap;
|
|
use std::sync::{LazyLock, Mutex};
|
|
|
|
static BRANDING: Dir<'static> = include_dir!("$CARGO_MANIFEST_DIR/../../branding/assets");
|
|
|
|
const RASTER_SCALE: f32 = 2.0;
|
|
|
|
static CACHE: LazyLock<Mutex<HashMap<&'static str, Handle>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
|
|
|
|
pub fn icon_handle(name: &str) -> Option<Handle> {
|
|
let (key, path, size) = lookup(name)?;
|
|
|
|
if let Some(cached) = CACHE.lock().ok().and_then(|c| c.get(key).cloned()) {
|
|
return Some(cached);
|
|
}
|
|
|
|
let bytes = BRANDING.get_file(path)?.contents();
|
|
let handle = if path.ends_with(".svg") {
|
|
rasterize_svg(bytes, size)?
|
|
} else {
|
|
decode_raster(bytes)?
|
|
};
|
|
|
|
if let Ok(mut cache) = CACHE.lock() {
|
|
cache.insert(key, handle.clone());
|
|
}
|
|
Some(handle)
|
|
}
|
|
|
|
fn rasterize_svg(bytes: &[u8], size: Option<u32>) -> Option<Handle> {
|
|
let opt = usvg::Options::default();
|
|
let tree = usvg::Tree::from_data(bytes, &opt).ok()?;
|
|
let svg_size = tree.size();
|
|
|
|
let (width, height) = match size {
|
|
Some(s) => {
|
|
let s_f = s as f32 * RASTER_SCALE;
|
|
(s_f.max(1.0).round() as u32, s_f.max(1.0).round() as u32)
|
|
}
|
|
None => {
|
|
let w = (svg_size.width() * RASTER_SCALE).max(1.0).round() as u32;
|
|
let h = (svg_size.height() * RASTER_SCALE).max(1.0).round() as u32;
|
|
(w, h)
|
|
}
|
|
};
|
|
|
|
let scale_x = width as f32 / svg_size.width();
|
|
let scale_y = height as f32 / svg_size.height();
|
|
let transform = tiny_skia::Transform::from_scale(scale_x, scale_y);
|
|
|
|
let mut pixmap = tiny_skia::Pixmap::new(width, height)?;
|
|
resvg::render(&tree, transform, &mut pixmap.as_mut());
|
|
|
|
let rgba = pixmap.take_demultiplied();
|
|
Some(Handle::from_rgba(width, height, rgba))
|
|
}
|
|
|
|
fn decode_raster(bytes: &[u8]) -> Option<Handle> {
|
|
let img = image::load_from_memory(bytes).ok()?.to_rgba8();
|
|
let (w, h) = img.dimensions();
|
|
Some(Handle::from_rgba(w, h, img.into_raw()))
|
|
}
|
|
|
|
fn lookup(name: &str) -> Option<(&'static str, &'static str, Option<u32>)> {
|
|
for &(n, path, size) in ICONS {
|
|
if n == name {
|
|
return Some((n, path, size));
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
const ICONS: &[(&str, &str, Option<u32>)] = &[
|
|
("GraphiteLogotypeSolid", "graphics/graphite-logotype-solid.svg", None),
|
|
("Add", "icon-12px-solid/add.svg", Some(12)),
|
|
("Checkmark", "icon-12px-solid/checkmark.svg", Some(12)),
|
|
("Clipped", "icon-12px-solid/clipped.svg", Some(12)),
|
|
("CloseX", "icon-12px-solid/close-x.svg", Some(12)),
|
|
("Delay", "icon-12px-solid/delay.svg", Some(12)),
|
|
("Dot", "icon-12px-solid/dot.svg", Some(12)),
|
|
("DotThick", "icon-12px-solid/dot-thick.svg", Some(12)),
|
|
("DropdownArrow", "icon-12px-solid/dropdown-arrow.svg", Some(12)),
|
|
("Edit12px", "icon-12px-solid/edit-12px.svg", Some(12)),
|
|
("Empty12px", "icon-12px-solid/empty-12px.svg", Some(12)),
|
|
("Failure", "icon-12px-solid/failure.svg", Some(12)),
|
|
("FullscreenEnter", "icon-12px-solid/fullscreen-enter.svg", Some(12)),
|
|
("FullscreenExit", "icon-12px-solid/fullscreen-exit.svg", Some(12)),
|
|
("Grid", "icon-12px-solid/grid.svg", Some(12)),
|
|
("GridDotted", "icon-12px-solid/grid-dotted.svg", Some(12)),
|
|
("Info", "icon-12px-solid/info.svg", Some(12)),
|
|
("KeyboardArrowDown", "icon-12px-solid/keyboard-arrow-down.svg", Some(12)),
|
|
("KeyboardArrowLeft", "icon-12px-solid/keyboard-arrow-left.svg", Some(12)),
|
|
("KeyboardArrowRight", "icon-12px-solid/keyboard-arrow-right.svg", Some(12)),
|
|
("KeyboardArrowUp", "icon-12px-solid/keyboard-arrow-up.svg", Some(12)),
|
|
("KeyboardBackspace", "icon-12px-solid/keyboard-backspace.svg", Some(12)),
|
|
("KeyboardCommand", "icon-12px-solid/keyboard-command.svg", Some(12)),
|
|
("KeyboardControl", "icon-12px-solid/keyboard-control.svg", Some(12)),
|
|
("KeyboardEnter", "icon-12px-solid/keyboard-enter.svg", Some(12)),
|
|
("KeyboardOption", "icon-12px-solid/keyboard-option.svg", Some(12)),
|
|
("KeyboardShift", "icon-12px-solid/keyboard-shift.svg", Some(12)),
|
|
("KeyboardSpace", "icon-12px-solid/keyboard-space.svg", Some(12)),
|
|
("KeyboardTab", "icon-12px-solid/keyboard-tab.svg", Some(12)),
|
|
("License12px", "icon-12px-solid/license-12px.svg", Some(12)),
|
|
("Link", "icon-12px-solid/link.svg", Some(12)),
|
|
("Overlays", "icon-12px-solid/overlays.svg", Some(12)),
|
|
("Remove", "icon-12px-solid/remove.svg", Some(12)),
|
|
("RenderModeNormal", "icon-12px-solid/render-mode-normal.svg", Some(12)),
|
|
("RenderModeOutline", "icon-12px-solid/render-mode-outline.svg", Some(12)),
|
|
("RenderModePixels", "icon-12px-solid/render-mode-pixels.svg", Some(12)),
|
|
("RenderModeSvg", "icon-12px-solid/render-mode-svg.svg", Some(12)),
|
|
("Snapping", "icon-12px-solid/snapping.svg", Some(12)),
|
|
("SwapHorizontal", "icon-12px-solid/swap-horizontal.svg", Some(12)),
|
|
("SwapVertical", "icon-12px-solid/swap-vertical.svg", Some(12)),
|
|
("VerticalEllipsis", "icon-12px-solid/vertical-ellipsis.svg", Some(12)),
|
|
("Warning", "icon-12px-solid/warning.svg", Some(12)),
|
|
("WindowButtonWinClose", "icon-12px-solid/window-button-win-close.svg", Some(12)),
|
|
("WindowButtonWinMaximize", "icon-12px-solid/window-button-win-maximize.svg", Some(12)),
|
|
("WindowButtonWinMinimize", "icon-12px-solid/window-button-win-minimize.svg", Some(12)),
|
|
("WindowButtonWinRestoreDown", "icon-12px-solid/window-button-win-restore-down.svg", Some(12)),
|
|
("WorkingColors", "icon-12px-solid/working-colors.svg", Some(12)),
|
|
("AlignBottom", "icon-16px-solid/align-bottom.svg", Some(16)),
|
|
("AlignHorizontalCenter", "icon-16px-solid/align-horizontal-center.svg", Some(16)),
|
|
("AlignLeft", "icon-16px-solid/align-left.svg", Some(16)),
|
|
("AlignRight", "icon-16px-solid/align-right.svg", Some(16)),
|
|
("AlignTop", "icon-16px-solid/align-top.svg", Some(16)),
|
|
("AlignVerticalCenter", "icon-16px-solid/align-vertical-center.svg", Some(16)),
|
|
("Artboard", "icon-16px-solid/artboard.svg", Some(16)),
|
|
("BooleanDifference", "icon-16px-solid/boolean-difference.svg", Some(16)),
|
|
("BooleanDivide", "icon-16px-solid/boolean-divide.svg", Some(16)),
|
|
("BooleanIntersect", "icon-16px-solid/boolean-intersect.svg", Some(16)),
|
|
("BooleanSubtractBack", "icon-16px-solid/boolean-subtract-back.svg", Some(16)),
|
|
("BooleanSubtractFront", "icon-16px-solid/boolean-subtract-front.svg", Some(16)),
|
|
("BooleanUnion", "icon-16px-solid/boolean-union.svg", Some(16)),
|
|
("Bug", "icon-16px-solid/bug.svg", Some(16)),
|
|
("CheckboxChecked", "icon-16px-solid/checkbox-checked.svg", Some(16)),
|
|
("CheckboxUnchecked", "icon-16px-solid/checkbox-unchecked.svg", Some(16)),
|
|
("Close", "icon-16px-solid/close.svg", Some(16)),
|
|
("CloseAll", "icon-16px-solid/close-all.svg", Some(16)),
|
|
("Code", "icon-16px-solid/code.svg", Some(16)),
|
|
("Copy", "icon-16px-solid/copy.svg", Some(16)),
|
|
("Credits", "icon-16px-solid/credits.svg", Some(16)),
|
|
("CustomColor", "icon-16px-solid/custom-color.svg", Some(16)),
|
|
("Cut", "icon-16px-solid/cut.svg", Some(16)),
|
|
("DeselectAll", "icon-16px-solid/deselect-all.svg", Some(16)),
|
|
("Edit", "icon-16px-solid/edit.svg", Some(16)),
|
|
("Empty", "icon-16px-solid/empty.svg", Some(16)),
|
|
("ExpandFillStroke", "icon-16px-solid/expand-fill-stroke.svg", Some(16)),
|
|
("Eyedropper", "icon-16px-solid/eyedropper.svg", Some(16)),
|
|
("EyeHidden", "icon-16px-solid/eye-hidden.svg", Some(16)),
|
|
("EyeHide", "icon-16px-solid/eye-hide.svg", Some(16)),
|
|
("EyeShow", "icon-16px-solid/eye-show.svg", Some(16)),
|
|
("EyeVisible", "icon-16px-solid/eye-visible.svg", Some(16)),
|
|
("File", "icon-16px-solid/file.svg", Some(16)),
|
|
("FileExport", "icon-16px-solid/file-export.svg", Some(16)),
|
|
("FileImport", "icon-16px-solid/file-import.svg", Some(16)),
|
|
("FlipHorizontal", "icon-16px-solid/flip-horizontal.svg", Some(16)),
|
|
("FlipVertical", "icon-16px-solid/flip-vertical.svg", Some(16)),
|
|
("Folder", "icon-16px-solid/folder.svg", Some(16)),
|
|
("FolderOpen", "icon-16px-solid/folder-open.svg", Some(16)),
|
|
("FrameAll", "icon-16px-solid/frame-all.svg", Some(16)),
|
|
("FrameSelected", "icon-16px-solid/frame-selected.svg", Some(16)),
|
|
("GraphiteLogo", "icon-16px-solid/graphite-logo.svg", Some(16)),
|
|
("GraphViewClosed", "icon-16px-solid/graph-view-closed.svg", Some(16)),
|
|
("GraphViewOpen", "icon-16px-solid/graph-view-open.svg", Some(16)),
|
|
("HandleVisibilityAll", "icon-16px-solid/handle-visibility-all.svg", Some(16)),
|
|
("HandleVisibilityFrontier", "icon-16px-solid/handle-visibility-frontier.svg", Some(16)),
|
|
("HandleVisibilitySelected", "icon-16px-solid/handle-visibility-selected.svg", Some(16)),
|
|
("Heart", "icon-16px-solid/heart.svg", Some(16)),
|
|
("HistoryRedo", "icon-16px-solid/history-redo.svg", Some(16)),
|
|
("HistoryUndo", "icon-16px-solid/history-undo.svg", Some(16)),
|
|
("IconsGrid", "icon-16px-solid/icons-grid.svg", Some(16)),
|
|
("Image", "icon-16px-solid/image.svg", Some(16)),
|
|
("InterpolationBlend", "icon-16px-solid/interpolation-blend.svg", Some(16)),
|
|
("InterpolationMorph", "icon-16px-solid/interpolation-morph.svg", Some(16)),
|
|
("Layer", "icon-16px-solid/layer.svg", Some(16)),
|
|
("License", "icon-16px-solid/license.svg", Some(16)),
|
|
("NewLayer", "icon-16px-solid/new-layer.svg", Some(16)),
|
|
("Node", "icon-16px-solid/node.svg", Some(16)),
|
|
("NodeBlur", "icon-16px-solid/node-blur.svg", Some(16)),
|
|
("NodeBrushwork", "icon-16px-solid/node-brushwork.svg", Some(16)),
|
|
("NodeColorCorrection", "icon-16px-solid/node-color-correction.svg", Some(16)),
|
|
("NodeGradient", "icon-16px-solid/node-gradient.svg", Some(16)),
|
|
("NodeMagicWand", "icon-16px-solid/node-magic-wand.svg", Some(16)),
|
|
("NodeMask", "icon-16px-solid/node-mask.svg", Some(16)),
|
|
("NodeMotionBlur", "icon-16px-solid/node-motion-blur.svg", Some(16)),
|
|
("NodeNodes", "icon-16px-solid/node-nodes.svg", Some(16)),
|
|
("NodeOutput", "icon-16px-solid/node-output.svg", Some(16)),
|
|
("NodeShape", "icon-16px-solid/node-shape.svg", Some(16)),
|
|
("NodeText", "icon-16px-solid/node-text.svg", Some(16)),
|
|
("NodeTransform", "icon-16px-solid/node-transform.svg", Some(16)),
|
|
("PadlockLocked", "icon-16px-solid/padlock-locked.svg", Some(16)),
|
|
("PadlockUnlocked", "icon-16px-solid/padlock-unlocked.svg", Some(16)),
|
|
("Paste", "icon-16px-solid/paste.svg", Some(16)),
|
|
("PinActive", "icon-16px-solid/pin-active.svg", Some(16)),
|
|
("PinInactive", "icon-16px-solid/pin-inactive.svg", Some(16)),
|
|
("PlaybackPause", "icon-16px-solid/playback-pause.svg", Some(16)),
|
|
("PlaybackPlay", "icon-16px-solid/playback-play.svg", Some(16)),
|
|
("PlaybackToEnd", "icon-16px-solid/playback-to-end.svg", Some(16)),
|
|
("PlaybackToStart", "icon-16px-solid/playback-to-start.svg", Some(16)),
|
|
("Random", "icon-16px-solid/random.svg", Some(16)),
|
|
("Reload", "icon-16px-solid/reload.svg", Some(16)),
|
|
("Reset", "icon-16px-solid/reset.svg", Some(16)),
|
|
("Resync", "icon-16px-solid/resync.svg", Some(16)),
|
|
("Reverse", "icon-16px-solid/reverse.svg", Some(16)),
|
|
("ReverseRadialGradientToLeft", "icon-16px-solid/reverse-radial-gradient-to-left.svg", Some(16)),
|
|
("ReverseRadialGradientToRight", "icon-16px-solid/reverse-radial-gradient-to-right.svg", Some(16)),
|
|
("Save", "icon-16px-solid/save.svg", Some(16)),
|
|
("SelectAll", "icon-16px-solid/select-all.svg", Some(16)),
|
|
("SelectParent", "icon-16px-solid/select-parent.svg", Some(16)),
|
|
("Settings", "icon-16px-solid/settings.svg", Some(16)),
|
|
("SmallDot", "icon-16px-solid/small-dot.svg", Some(16)),
|
|
("Stack", "icon-16px-solid/stack.svg", Some(16)),
|
|
("StackBottom", "icon-16px-solid/stack-bottom.svg", Some(16)),
|
|
("StackHollow", "icon-16px-solid/stack-hollow.svg", Some(16)),
|
|
("StackLower", "icon-16px-solid/stack-lower.svg", Some(16)),
|
|
("StackRaise", "icon-16px-solid/stack-raise.svg", Some(16)),
|
|
("StackReverse", "icon-16px-solid/stack-reverse.svg", Some(16)),
|
|
("StrokeAlignCenter", "icon-16px-solid/stroke-align-center.svg", Some(16)),
|
|
("StrokeAlignInside", "icon-16px-solid/stroke-align-inside.svg", Some(16)),
|
|
("StrokeAlignOutside", "icon-16px-solid/stroke-align-outside.svg", Some(16)),
|
|
("StrokeCapButt", "icon-16px-solid/stroke-cap-butt.svg", Some(16)),
|
|
("StrokeCapRound", "icon-16px-solid/stroke-cap-round.svg", Some(16)),
|
|
("StrokeCapSquare", "icon-16px-solid/stroke-cap-square.svg", Some(16)),
|
|
("StrokeJoinBevel", "icon-16px-solid/stroke-join-bevel.svg", Some(16)),
|
|
("StrokeJoinMiter", "icon-16px-solid/stroke-join-miter.svg", Some(16)),
|
|
("StrokeJoinRound", "icon-16px-solid/stroke-join-round.svg", Some(16)),
|
|
("StrokeOrderAbove", "icon-16px-solid/stroke-order-above.svg", Some(16)),
|
|
("StrokeOrderBelow", "icon-16px-solid/stroke-order-below.svg", Some(16)),
|
|
("TextAlignCenter", "icon-16px-solid/text-align-center.svg", Some(16)),
|
|
("TextAlignLeft", "icon-16px-solid/text-align-left.svg", Some(16)),
|
|
("TextAlignRight", "icon-16px-solid/text-align-right.svg", Some(16)),
|
|
("TextAlignSpineAway", "icon-16px-solid/text-align-spine-away.svg", Some(16)),
|
|
("TextAlignSpineTowards", "icon-16px-solid/text-align-spine-towards.svg", Some(16)),
|
|
("TextJustifyAll", "icon-16px-solid/text-justify-all.svg", Some(16)),
|
|
("TextJustifyCenter", "icon-16px-solid/text-justify-center.svg", Some(16)),
|
|
("TextJustifyLeft", "icon-16px-solid/text-justify-left.svg", Some(16)),
|
|
("TextJustifyRight", "icon-16px-solid/text-justify-right.svg", Some(16)),
|
|
("Tilt", "icon-16px-solid/tilt.svg", Some(16)),
|
|
("TiltReset", "icon-16px-solid/tilt-reset.svg", Some(16)),
|
|
("TransformationGrab", "icon-16px-solid/transformation-grab.svg", Some(16)),
|
|
("TransformationRotate", "icon-16px-solid/transformation-rotate.svg", Some(16)),
|
|
("TransformationScale", "icon-16px-solid/transformation-scale.svg", Some(16)),
|
|
("Trash", "icon-16px-solid/trash.svg", Some(16)),
|
|
("TurnNegative90", "icon-16px-solid/turn-negative-90.svg", Some(16)),
|
|
("TurnPositive90", "icon-16px-solid/turn-positive-90.svg", Some(16)),
|
|
("UserManual", "icon-16px-solid/user-manual.svg", Some(16)),
|
|
("ViewportDesignMode", "icon-16px-solid/viewport-design-mode.svg", Some(16)),
|
|
("ViewportGuideMode", "icon-16px-solid/viewport-guide-mode.svg", Some(16)),
|
|
("ViewportSelectMode", "icon-16px-solid/viewport-select-mode.svg", Some(16)),
|
|
("Volunteer", "icon-16px-solid/volunteer.svg", Some(16)),
|
|
("Website", "icon-16px-solid/website.svg", Some(16)),
|
|
("WorkingColorsPrimary", "icon-16px-solid/working-colors-primary.svg", Some(16)),
|
|
("WorkingColorsSecondary", "icon-16px-solid/working-colors-secondary.svg", Some(16)),
|
|
("Zoom1x", "icon-16px-solid/zoom-1x.svg", Some(16)),
|
|
("Zoom2x", "icon-16px-solid/zoom-2x.svg", Some(16)),
|
|
("ZoomIn", "icon-16px-solid/zoom-in.svg", Some(16)),
|
|
("ZoomOut", "icon-16px-solid/zoom-out.svg", Some(16)),
|
|
("ZoomReset", "icon-16px-solid/zoom-reset.svg", Some(16)),
|
|
("MouseHintDrag", "icon-16px-two-tone/mouse-hint-drag.svg", Some(16)),
|
|
("MouseHintLmb", "icon-16px-two-tone/mouse-hint-lmb.svg", Some(16)),
|
|
("MouseHintLmbDouble", "icon-16px-two-tone/mouse-hint-lmb-double.svg", Some(16)),
|
|
("MouseHintLmbDrag", "icon-16px-two-tone/mouse-hint-lmb-drag.svg", Some(16)),
|
|
("MouseHintMmb", "icon-16px-two-tone/mouse-hint-mmb.svg", Some(16)),
|
|
("MouseHintMmbDrag", "icon-16px-two-tone/mouse-hint-mmb-drag.svg", Some(16)),
|
|
("MouseHintNone", "icon-16px-two-tone/mouse-hint-none.svg", Some(16)),
|
|
("MouseHintRmb", "icon-16px-two-tone/mouse-hint-rmb.svg", Some(16)),
|
|
("MouseHintRmbDouble", "icon-16px-two-tone/mouse-hint-rmb-double.svg", Some(16)),
|
|
("MouseHintRmbDrag", "icon-16px-two-tone/mouse-hint-rmb-drag.svg", Some(16)),
|
|
("MouseHintScrollDown", "icon-16px-two-tone/mouse-hint-scroll-down.svg", Some(16)),
|
|
("MouseHintScrollUp", "icon-16px-two-tone/mouse-hint-scroll-up.svg", Some(16)),
|
|
("GeneralArtboardTool", "icon-24px-two-tone/general-artboard-tool.svg", Some(24)),
|
|
("GeneralEyedropperTool", "icon-24px-two-tone/general-eyedropper-tool.svg", Some(24)),
|
|
("GeneralFillTool", "icon-24px-two-tone/general-fill-tool.svg", Some(24)),
|
|
("GeneralGradientTool", "icon-24px-two-tone/general-gradient-tool.svg", Some(24)),
|
|
("GeneralNavigateTool", "icon-24px-two-tone/general-navigate-tool.svg", Some(24)),
|
|
("GeneralSelectTool", "icon-24px-two-tone/general-select-tool.svg", Some(24)),
|
|
("RasterBrushTool", "icon-24px-two-tone/raster-brush-tool.svg", Some(24)),
|
|
("RasterCloneTool", "icon-24px-two-tone/raster-clone-tool.svg", Some(24)),
|
|
("RasterDetailTool", "icon-24px-two-tone/raster-detail-tool.svg", Some(24)),
|
|
("RasterHealTool", "icon-24px-two-tone/raster-heal-tool.svg", Some(24)),
|
|
("RasterPatchTool", "icon-24px-two-tone/raster-patch-tool.svg", Some(24)),
|
|
("RasterRelightTool", "icon-24px-two-tone/raster-relight-tool.svg", Some(24)),
|
|
("VectorEllipseTool", "icon-24px-two-tone/vector-ellipse-tool.svg", Some(24)),
|
|
("VectorFreehandTool", "icon-24px-two-tone/vector-freehand-tool.svg", Some(24)),
|
|
("VectorLineTool", "icon-24px-two-tone/vector-line-tool.svg", Some(24)),
|
|
("VectorPathTool", "icon-24px-two-tone/vector-path-tool.svg", Some(24)),
|
|
("VectorPenTool", "icon-24px-two-tone/vector-pen-tool.svg", Some(24)),
|
|
("VectorPolygonTool", "icon-24px-two-tone/vector-polygon-tool.svg", Some(24)),
|
|
("VectorRectangleTool", "icon-24px-two-tone/vector-rectangle-tool.svg", Some(24)),
|
|
("VectorSplineTool", "icon-24px-two-tone/vector-spline-tool.svg", Some(24)),
|
|
("VectorTextTool", "icon-24px-two-tone/vector-text-tool.svg", Some(24)),
|
|
];
|