SvgIcon
WHY THIS IS NOT JUST A GENERIC SVG RENDERER The point of this class is not to draw arbitrary SVG art. It is to let an SVG-authored icon become a first-class Grasshopper icon that participates in Grasshopper's runtime icon theming. A normal SVG (and any SVG we rasterise to a bitmap) bakes its colours into fixed RGB pixels; those pixels cannot react to the user's theme. By parsing the SVG once into native VectorElements, every colour is re-resolved on each redraw through IconContext.ResolveSpecialColour(Color) — exactly like a hand-authored vector icon. As a bonus the result is resolution-independent (no bitmap, so none of the Windows DrawImage upsampling trouble that plagues raster icons), and it responds to the desaturate / flatten / high-contrast icon filters for free.
THE SPECIAL-COLOUR CONCEPT (the whole reason this class exists) Grasshopper does not think of icon colours as fixed RGB values. It thinks in semantic roles — see the SpecialColour enum. A role such as SpecialColour.Foreground or SpecialColour.Input is resolved to an actual colour at draw time, taking into account the background the icon is sitting on (so it adapts between light and dark themes), the user-configurable palette, and any active filter. That is why a role-authored icon "just works" on a dark canvas, on a light canvas, when desaturated, and after the user recolours their palette — the artwork never changed, only the resolution of its roles did.
Grasshopper's palette carries roles that mean something about a component's function, so an icon can speak the same visual language as the rest of the UI:
- SpecialColour.Input — the colour family for input / parameter-like things.
- SpecialColour.Output — for components that produce / generate something.
- SpecialColour.Analysis — for components that measure / analyse existing data.
- SpecialColour.Symbolic — for abstract / symbolic operations.
- SpecialColour.Foreground / SpecialColour.Background — the neutral figure/ground pair, with
FirmandStarkvariants for stronger contrast. - SpecialColour.Warning, SpecialColour.Error, SpecialColour.Hint, SpecialColour.Success, SpecialColour.Selected — status signals.
Input, Output, Analysis, Symbolic) also exposes a set of coordinated shades — …Shine (brightest), …Light, the base role, …Dark, and …Edge (for outlines against the background). Authoring an icon's highlights and shadows from one family's shades makes the whole icon re-shade coherently when the palette or theme changes: swap every gh:Input for gh:Output and the same artwork becomes a correctly-shaded "output" icon. HOW AN AUTHOR OPTS INTO A ROLE (the theming hook in the SVG) A paint value of the form fill="gh:Foreground" (or the long form fill="gh-special:Input") is mapped to the matching SpecialColour and stays themeable; the name after the prefix is any member of the SpecialColour enum, case-insensitively. fill="currentColor" is shorthand for SpecialColour.Foreground. An unrecognised role name renders as deep pink so the mistake is obvious. Any ordinary CSS colour (hex / rgb() / named) becomes a constant, non-themeable colour, exactly as in a normal SVG. An element with no fill specified at all defaults to the themeable SpecialColour.Foreground role (NOT SVG's literal black) so an un-annotated component icon stays legible on any background. These roles are inherited through <g> groups like any other SVG presentation attribute.
SUPPORTED SVG SUBSET Deliberately the flat-fill component-icon subset that maps cleanly onto the native vector vocabulary (see the demo .svg for authoring notes):
- Elements:
g, rect, circle, ellipse, line, polyline, polygon, path.defs, title, desc, metadata, styleare parsed and skipped; any other element is ignored. - Path
dcommands:M L H V C S Q T Z, absolute and relative, including the smooth-curve shorthandsS/T(control-point reflection). - Paint / presentation:
fill, stroke, stroke-width, fill-opacity, stroke-opacity, given either as attributes or insidestyle="…", and inherited through<g>. - Sizing:
viewBox(preferred) elsewidth/height; a trailing unit such aspxon a length is tolerated.
NOT SUPPORTED (by design, for this PoC)
- Gradients —
<linearGradient>/<radialGradient>andfill="url(#…)"are NOT supported. (The nativeLinearFill/RadialFilltypes could carry these in a later pass; for now, a gradient paint is unrecognised and renders as deep pink.) Author multi-tone shading with the palette's shade family instead — that is what themes correctly anyway. - Elliptical-arc path command
A— its 7 parameters are consumed and it is approximated by a straight line to the endpoint. Pre-flatten arcs, or usecircle/ellipse. transformattributes — ignored. Geometry must be authored in the final viewBox coordinate system (flatten transforms in your editor before export). TheviewBoxis also assumed to start at0,0; a non-zero origin is not compensated for.clipPath,mask,<filter>effects, opacity on groups, rounded-rect corners (rx/ry), and even-odd "holes" (each sub-path is filled on its own rather than being subtracted).- Per-element opacity applied on top of an inherited themeable role is ignored rather than baked into a constant, so the role keeps its theming (see ApplyPresentation).
Methods
FromResource
#nameFragment (case-insensitive) is used, so callers can pass a short file name without the namespace prefix.FromXml
#| svg (string) | SVG XML. |