Class Theme
builtins()):
light()/dark(), the project's own limn() and
limnLight(), plus
ones drawn from familiar editor palettes (Darkling, Draculite, Nordic,
Arch Dark, Onyx Dark, Monoko Pro, Grovebox Dark, Solaris light/dark,
GitHub light, High contrast).
The active theme is process-wide (current()/setCurrent(limn.components.Theme)).
After switching, call root.markNeedsLayout() so sizes/typography update.
An application can build its own. builder(String, boolean) starts from
a working palette and toBuilder() starts from this one, so a palette of your own
costs only the tones that make it yours; Theme.Token enumerates them so that
code treating them alike does not have to name all of them.
What a palette carries is colour, plus one metric: cornerScale, how
round the corners are. Spacing and typography stay process-wide and identical in every
palette; see tokens(limn.scene.ControlSize) for why that boundary falls exactly where it does, and why
a radius is the one metric allowed across it.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classCollects the colours of a palette and builds one.static enumEvery colour a palette is made of, as values, so that code which has to treat every tone alike (a serializer, an editor, a contrast report) enumerates them instead of naming them all and getting all but one right. -
Field Summary
FieldsModifier and TypeFieldDescriptionfinal EasingDefault timing curve for state transitions.final doubleGeneric show/hide and value fades: the progress bar, a chart's entry animation, and the check and dot marks.final doubleFocus-ring fade in/out.final doubleHover fade in/out (buttons, tabs, combo, rows).final doubleSelected-tab indicator slide (TabbedPane).final doubleWhole-window show/hide fade (native dialogs, popups, floating windows).final Colorfinal Fontfinal floatHow round the corners are, as a multiplier on every radius in the size table: 0 for square, 1 for the shipped ramp, above 1 for softer, and far enough above for a pill (a radius past half the shorter side is capped when it is drawn).final ColorError / destructive (red).final booleanWhether this is a dark palette (lets callers group/pick a sensible default).final Colorfinal Colorfinal Colorfinal StringThe typeface family this palette asks for, orFont.DEFAULT_FAMILY: the value it carries when a palette expresses no preference, and the one every built-in carries.final ColorInformational / neutral accent (blue).final Fontstatic final floatThe largestcornerScalea palette may ask for.final StringHuman-readable name, the label a theme picker shows.final Colorfinal Colorfinal Colorfinal Colorfinal Colorfinal ColorThe veil an in-scene modal dialog paints over everything beneath it, alpha included: the one tone in a palette whose alpha carries meaning.final floatfinal floatfinal floatfinal ColorSuccess / valid (green).final Colorfinal Colorfinal Colorfinal Colorfinal Fontfinal ColorWarning / caution (amber). -
Method Summary
Modifier and TypeMethodDescriptionvoidAsksFontsto resolveFont.DEFAULT_FAMILYto this palette'sfontFamily: the act that makes a palette's type preference visible.static Theme.Builderbuiltins()Every palette that ships with the toolkit, in presentation order.static Themecurrent()static Themedark()The built-in dark palette.The name a picker shows, in the UI language;namestays the identifier.booleanTwo palettes are equal when they carry the same name, mode, shape, typeface preference and colours, which is everything a palette is, and everythingThemeFormatwrites.inthashCode()static Themelight()The built-in light palette.static Themelimn()The project's own palette: a deep violet canvas with a vivid violet accent, tuned so that body text, muted text, the accent's own label and the focus ring each clear WCAG AA on the surface they land on.static ThemeThe light companion tolimn(), held to the same contrast targets.static voidsetCurrent(Theme theme) Switches the process-wide palette.This palette's tones, in a builder: the form to start from when an application wants a built-in with two things changed rather than a palette of its own.final SizeTokenstokens(ControlSize size) Metric tokens for a size step.final SizeTokensTokens for the step resolved onwidget, the one line components call.toString()The palette's name.
-
Field Details
-
MAX_CORNER_SCALE
public static final float MAX_CORNER_SCALEThe largestcornerScalea palette may ask for. Past this every control in the toolkit is already a pill (a radius beyond half the shorter side is capped when it is drawn), so a higher number would change nothing and only look like it might.- See Also:
-
name
Human-readable name, the label a theme picker shows. -
dark
public final boolean darkWhether this is a dark palette (lets callers group/pick a sensible default). -
background
-
surface
-
surfaceRaised
-
-
primaryHover
-
primaryPressed
-
onPrimary
-
text
-
textMuted
-
outline
-
focusRing
-
disabledFill
-
disabledText
-
scrim
The veil an in-scene modal dialog paints over everything beneath it, alpha included: the one tone in a palette whose alpha carries meaning. It is painted once, over the whole scene, and the card sits on top of it.Between transparent and opaque, and neither end is usable: at alpha 0 nothing behind the card dims and there is no sign the rest of the window has stopped accepting input, and at alpha 1 the content behind the card is gone rather than blocked.
ThemeContrastTestholds every shipped palette between those.A window blocked by a native modal is dimmed by the scene, not by this. That veil lives a layer below, where no palette can be seen at all, so moving this tone does not move it and the two are only ever approximately alike.
-
danger
Error / destructive (red). -
success
Success / valid (green). -
warning
Warning / caution (amber). -
info
Informational / neutral accent (blue). -
cornerScale
public final float cornerScaleHow round the corners are, as a multiplier on every radius in the size table: 0 for square, 1 for the shipped ramp, above 1 for softer, and far enough above for a pill (a radius past half the shorter side is capped when it is drawn).The one metric a palette carries, and it is here rather than in the size table because it is the only one nothing measures from: not one
onMeasure,onLayout,baselineOffsetorpaintOutsetin this toolkit reads a radius, so a change of shape is a repaint exactly like a change of colour.ThemeShapeTestasserts that, and it is what the whole design rests on; seetokens(limn.scene.ControlSize). -
fontFamily
The typeface family this palette asks for, orFont.DEFAULT_FAMILY: the value it carries when a palette expresses no preference, and the one every built-in carries.A declaration, not a resolution. Nothing here reads a font file or checks that the family exists; a palette is a value and stays one. What acts on it is
applyFontFamily(), which hands the name toFonts.setDefaultFamily(java.lang.String), and that is where the fallback lives: a family the backend cannot resolve, including every family on a machine that does not have it installed, renders in the toolkit's embedded Roboto. Naming a font that only exists on the designer's laptop therefore degrades to the shipped face rather than to tofu or to an exception.Why this is a name and not a
Fonton the size rows. Type is measured from, andsetCurrent(limn.components.Theme)notifies nobody; seetokens(limn.scene.ControlSize). Baking the family into the five rows would change every text measurement in every live window with no relayout anywhere.Font.DEFAULT_FAMILYis resolved late, by the backend, andFontsalready notifies its listeners so that scenes re-lay-out; routing a palette's type preference through that mechanism is the only shape that does not need a theme-change listener this repository does not have. -
body
-
label
-
title
-
spacingSmall
public final float spacingSmall- See Also:
-
spacingMedium
public final float spacingMedium- See Also:
-
spacingLarge
public final float spacingLarge- See Also:
-
animEasing
Default timing curve for state transitions. -
animHover
public final double animHoverHover fade in/out (buttons, tabs, combo, rows).- See Also:
-
animFocus
public final double animFocusFocus-ring fade in/out.- See Also:
-
animFade
public final double animFadeGeneric show/hide and value fades: the progress bar, a chart's entry animation, and the check and dot marks. Deliberately not the scrollbar, which declares its own four durations because its reveal is asymmetric (it appears fast and leaves slowly, after a hold), and no single token can say that.- See Also:
-
animTab
public final double animTabSelected-tab indicator slide (TabbedPane).- See Also:
-
animWindow
public final double animWindowWhole-window show/hide fade (native dialogs, popups, floating windows).- See Also:
-
-
Method Details
-
light
The built-in light palette. -
dark
The built-in dark palette. -
limn
The project's own palette: a deep violet canvas with a vivid violet accent, tuned so that body text, muted text, the accent's own label and the focus ring each clear WCAG AA on the surface they land on. -
limnLight
The light companion tolimn(), held to the same contrast targets. -
displayName
The name a picker shows, in the UI language;namestays the identifier. Only the descriptive palettes translate (Light,Dark,High Contrast); the rest are the names of the palettes they came from and read the same everywhere. -
builtins
Every palette that ships with the toolkit, in presentation order. -
current
- Returns:
- the process-wide active theme
-
tokens
Metric tokens for a size step. The returned record (and theFonts inside it) are stable for the life of this palette, so==holds and the backend's identity-keyed font memo keeps hitting. Never build tokens per call, and never callFont.withSizeto derive a step's font.Every metric here is palette-independent except the corner radii, which follow
cornerScale. At the default scale this returns the process-wide row itself, so a palette without a shape of its own is indistinguishable from what shipped before shape existed.Why the radii are allowed out and nothing else is.
setCurrent(limn.components.Theme)only assigns a volatile field (there is no theme-change listener anywhere in this repository), so a palette that could change a metric something measures from would change every measurement in every window with zero relayout. A radius is the one metric nothing measures from: noonMeasure,onLayout,baselineOffsetorpaintOutsetin this toolkit reads one, whichThemeShapeTestasserts by measuring a tree at two shapes and demanding the same numbers. Break that and shape stops being safe, not just the test.Two further traps stand in the way of any metric that is measured from. The six float token fields above are inlined at their call sites (JLS 13.1), so a per-palette value cannot reach a field read at all, which is exactly why the three radius fields are deprecated rather than made to follow the scale. And the nine token-backed fields read the static MEDIUM row, so they would be invisible to every unmigrated call site. If per-palette type or spacing is ever wanted, both prerequisites are required: route
setCurrentthrough the same weak per-scene registry asFonts/ControlSize, and initialize those fields fromthis.tokens(MEDIUM)in the constructor. -
tokensFor
Tokens for the step resolved onwidget, the one line components call. -
setCurrent
Switches the process-wide palette. Nothing is notified: callroot.markNeedsLayout()on each live scene afterwards, since type and spacing can differ between palettes. -
applyFontFamily
public void applyFontFamily()AsksFontsto resolveFont.DEFAULT_FAMILYto this palette'sfontFamily: the act that makes a palette's type preference visible.Separate from
setCurrent(limn.components.Theme)on purpose, and the separation is the contract: switching a palette is a repaint, while switching a font is a relayout and, the first time a face is named, a font file read inside the next frame.Fontssays so onFonts.setDefaultFamily(java.lang.String)and the rule it states applies here unchanged; call this from a settings screen or a theme picker, where one long frame reads as the switch happening, and never from an animation or a drag. Folding it intosetCurrentwould smuggle that read into every palette change, including the ones a colour well makes on every frame of a drag.A palette that expresses no preference carries
Font.DEFAULT_FAMILY, so calling this for one restores the toolkit's own face rather than leaving the previous palette's choice in place. Both directions are therefore safe to call unconditionally.UI thread.
-
builder
A palette of this application's own, seeded from the built-inlight()ordark()so that every tone is already a working one and only what makes the palette distinct has to be spelled out.Theme mine = Theme.builder("Ocean", true) .background(Color.rgb(0x0B1A24)) .surface(Color.rgb(0x11242F)) .surfaceRaised(Color.rgb(0x1A3340)) .primary(Color.rgb(0x4FD1C5)) .onPrimary(Color.rgb(0x04141A)) .deriveAccentStates() .deriveDisabled() .build(); Theme.setCurrent(mine);- Parameters:
name- the palette's identifier and its fallback display text; seeTheme.Builder.name, which explains why a name shared with a built-in is a name to avoiddark- whether the palette is dark, which decides the seed and which tones thederivemethods produce
-
toBuilder
This palette's tones, in a builder: the form to start from when an application wants a built-in with two things changed rather than a palette of its own.The theme is unaffected: a
Themeis immutable and the builder holds a copy. -
equals
Two palettes are equal when they carry the same name, mode, shape, typeface preference and colours, which is everything a palette is, and everythingThemeFormatwrites. The metrics do not appear here because they are process-wide: only the corner scale and the family name are a palette's to choose, and both are compared.Here so that an editor can ask "has this been changed" and a parser can be held to a round trip. The toolkit itself still compares the active palette by identity.
-
hashCode
public int hashCode() -
toString
The palette's name. A theme picker showsdisplayName(), not this.
-