MASS4.Guinevere.Styling
6.4.1
dotnet add package MASS4.Guinevere.Styling --version 6.4.1
NuGet\Install-Package MASS4.Guinevere.Styling -Version 6.4.1
<PackageReference Include="MASS4.Guinevere.Styling" Version="6.4.1" />
<PackageVersion Include="MASS4.Guinevere.Styling" Version="6.4.1" />
<PackageReference Include="MASS4.Guinevere.Styling" />
paket add MASS4.Guinevere.Styling --version 6.4.1
#r "nuget: MASS4.Guinevere.Styling, 6.4.1"
#:package MASS4.Guinevere.Styling@6.4.1
#addin nuget:?package=MASS4.Guinevere.Styling&version=6.4.1
#tool nuget:?package=MASS4.Guinevere.Styling&version=6.4.1
Guinevere.Styling
Runtime .pss (PanGui Style Sheet) theming for Guinevere. Styles are optional: the core library draws and lays out without them, so add this package only where sheets drive the look.
var theme = StyleSheetSource.FromFile("theme.pss");
gui.AddStyleSheet(theme);
gui.StyleSheets.SetToken("accent", "#ff8800"); // host override above every sheet
using (gui.StyledNode("button", classes: ["primary"]).Enter())
gui.DrawText("Save");
var style = gui.ResolveStyle("tooltip"); // read declarations for a self-drawn control
@const theme-name = "Night";
$base = #2e3440;
$accent = #88c0d0;
$contrast = 0.3;
$surface = shade($base, 1.1, 0.9); // Godot-style elevation ladder
button {
padding = 0.5em 1em;
bg-color = $surface;
color = contrast-ink($surface);
:hover(0.15 ease-out) { bg-color = mix($surface, $accent, 25%); }
}
gui.StyleSheets.GetTokenColor("surface") returns the evaluated token, so host code can use the same derived colors.
The package covers:
- Type, class, id, descendant and
>selectors. - Nesting,
#inheritand custom modifiers. $tokenslayered across sheets, and@constvalues the host can read.- Tokens inherited down the node tree like CSS custom properties: a rule's
$token = value;andgui.SetStyleToken(name, value)theme a node's whole subtree. - Value expressions: arithmetic,
calc(),em,min/max/clamp,rgb()/rgba()(every channel 0..255),rgb1()/rgba1()(every channel 0..1),hsl(),mix,alpha,lighten,darken,contrast-inkandshade. - Visual properties on
StyledNode:backgroundcolors andlinear-gradients,box-shadow(outer and inset), borders drawn inside the box (per side withborder-<side>-width/-color), per-cornerborder-radius,outline,opacity,cursor, and textcolor/font-*/text-shadowinherited by child text. - Icon themes:
icon#scene\.move { glyph = "\f0b2"; font-family = "fa6-solid"; }or{ src = url("move.png"); tint = true; }, drawn bygui.StyledIcon("scene.move", 16). @font-face,url()and@importthrough a host resolver.file:line:colerrors, and reloads that keep the last valid sheet.- Inspection:
gui.StyleSheets.MatchedRules(target)lists the rules an element uses, andStyleRule.Linespoints at their source. - A resolved-style cache whose hits allocate nothing.
Text shadows and glow
text-shadow = x y [blur] [color], ...; uses pixel lengths, including unitless pixels. Blur is a nonnegative CSS radius (twice the core Gaussian sigma), and omitted colors use the declaration's resolved text color. The first listed shadow paints above subsequent shadows, behind the glyph fill. Malformed declarations are ignored as a whole; percentages, spread and inset are unsupported.
Shadows inherit through node scopes into ordinary DrawText, glyphs and Excalibur controls. A local declaration replaces the inherited shadow list, and text-shadow = none; clears it for the subtree. An explicit DrawText(effects: ...) replaces all inherited effects for that draw; gui.SetTextEffects(...) provides the same scope mechanism to core callers. Shadows affect visual ink bounds and opacity layers while text measurement stays based on font metrics. Explicit text clips and ancestor clips apply to the effects too. Sheet reloads and host or subtree token changes refresh the resolved shadows; shadow lists change immediately rather than interpolating through transitions.
$phosphor = #66ff88;
terminal {
bg-color = #061009;
color = $phosphor;
font-family = monospace;
text-shadow = 0 0 4px $phosphor, 0 0 12px #33ff6680;
}
terminal .crisp { text-shadow = none; }
Example 50's styling page demonstrates this Terminal Green glow on a label and button. ResolvedStyle.GetTextShadows(defaultColor) exposes the typed list for custom controls. PanGui's published effects vocabulary includes innerShadow on shapes, but does not specify its text binding. Inner text effect syntax is deferred; shape effect blocks remain available in StyleSheet.Deferred, and core callers can use TextEffects.InnerShadow directly.
Font registration and roles
Register faces through gui.Fonts, or declare them in an active sheet. Numeric weights and italic faces are selected before synthetic bold or italic is applied. Later sheets replace matching family/weight/style descriptors; removing a sheet restores earlier faces. Missing files and unsupported remote sources leave other fallback families usable.
@font-face { font-family = "Brand"; src = url("fonts/Brand-Regular.ttf"); font-weight = 400; }
@font-face { font-family = "Brand"; src = url("fonts/Brand-Bold.ttf"); font-weight = 700; }
$font-ui = "Brand", "Noto Emoji";
$font-ui-mono = monospace;
$font-code = $font-ui-mono;
$font-icon = "fa6-solid";
$font-emoji = "Noto Emoji";
label { font-family = $font-ui; }
gui.Fonts.RegisterFile("Brand", "fonts/Brand-Regular.ttf");
gui.Fonts.RegisterStream("Symbols", fontStream);
gui.Fonts.SetRole(FontRole.Ui, "Brand, Noto Emoji");
gui.BeginFrame(canvas);
gui.UseFontRole(FontRole.Ui); // reads $font-ui, including host and subtree token overrides
using (gui.StyledNode("label").Enter())
gui.DrawText("Hello 😀");
var width = gui.MeasureTextWidth("Hello 😀", 14);
var codeFont = gui.ResolveFontRole(FontRole.Code, 14, weight: 700);
Call UseFontRole from the same call site in both passes. font-family lists fall back per Unicode code point, preserving surrogate pairs; MeasureTextWidth and GetTextFont share the renderer's scope font and DPI scaling. Display scaling is applied to logical text sizes and adjusted for an existing canvas scale. ConfigureFonts and the font-taking BeginFrame shortcuts register supplied faces while preserving configured defaults and per-frame overrides.
Custom controls can resolve declarations with gui.ResolveStyle and obtain their face with gui.GetStyleFont(style, scope). This preserves inherited weight and slant when a rule omits them, and retains fallback families.
The registry owns faces loaded from files/streams and fonts returned by lookup. Dispose gui.Fonts when the GUI is no longer used. Fonts passed to Register, ConfigureFonts or BeginFrame remain caller-owned. Shaping and ligatures are outside this API.
Bitmap backgrounds
background-image = url("tile.png"); (also accepted on background) loads a raster asset relative to the declaring sheet's BaseUri, including imported sheets. Files load directly; set StyleSheetOptions.ResourceResolver to open embedded resources or custom URI schemes. The resolver receives the resolved URI, and the returned stream is disposed after decoding. Unsupported or missing assets leave the solid background visible and appear in gui.BackgroundDiagnostics with the winning declaration's source, line and column.
The following vocabulary is provisional Guinevere syntax: PanGui's published styling overview establishes the = declaration and resource conventions but does not specify bitmap background properties.
background-repeat:repeat(default),repeat-x,repeat-y,no-repeat.background-size:auto(default, one bitmap pixel per logical unit),contain,cover, or one/two positive pixel or percentage lengths withautoallowed per axis. One explicit length sets width and preserves aspect ratio; percentages refer to the box dimensions.background-position: one/two pixel or percentage lengths orleft,center,right,top,bottom(default0% 0%). One value centers the other axis. Percentages position within the remaining space after sizing; negative offsets are allowed.
Images paint above the solid fill and below inset shadows and borders, clipped to the rounded border box. Transparent pixels reveal the fill. Node and part opacity, ancestor clips and canvas transforms apply normally. Dimensions are logical units; display/viewport scaling uses the same canvas transform as other geometry. Image layers, space/round repetition, four-value edge offsets and atlas regions are unsupported and produce diagnostics when a bitmap background is resolved.
Decoded images (including failed loads) are cached per GUI by URI and resolver, and resolved bitmap settings are cached with their styles. Sheet reloads/replacements and host token changes dispose and invalidate that cache; file changes alone do not reload it. Call gui.ClearBackgroundImages() between frames to refresh changed assets or release them at GUI shutdown. Native image wrappers are reclaimed with the GUI if no explicit cleanup is performed. Diagnostics are deduplicated until invalidation. Resolve/render a background before reading its diagnostics.
panel {
background-color = #203040;
background-image = url("surface.png");
background-repeat = no-repeat;
background-size = cover;
background-position = center;
border-radius = 8;
}
Example 50's Styling page includes embedded bitmap Win95 patterns, Luna and Aqua skins, and transparent CRT scanlines, selected entirely by stylesheet declarations.
Nine-slice backgrounds
Set background-slice alongside a bitmap background-image to stretch the center and edges while preserving the corners. Values are nonnegative source pixels, with optional px, in top/right/bottom/left order; one, two or three values expand like CSS edge values. none restores ordinary bitmap sizing and repetition.
.panel {
background-image = url("panel.png");
background-slice = 8 12 8 12;
}
A sliced image fills the border box; background-size, background-position and background-repeat do not change its slice placement. Insets clamp to the source image, and corners shrink proportionally if the destination is smaller than their combined size. Rounded clipping, solid fills beneath transparent pixels, shadows, borders, opacity and transforms apply as for other bitmap backgrounds. Invalid slice values produce located background diagnostics.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MASS4.Guinevere (>= 6.4.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on MASS4.Guinevere.Styling:
| Package | Downloads |
|---|---|
|
MASS4.Guinevere.Excalibur
A ready-to-use set of default Guinevere controls: buttons, inputs, tabs, tree, menu bar, flyout, popup, docking and more, built on the Guinevere core engine. |
GitHub repositories
This package is not used by any popular GitHub repositories.