Color scheme association kinds in Substance

April 17th, 2009

Color scheme association kinds in Substance look-and-feel are best illustrated by a simple example:

This is a screenshot of a JCheckBox icon under 72 point font. This checkmark icon has three different visual areas: inner fill, border and the “V” mark. Each one of these areas is painted with a different color scheme, and this is allowed by using the relevant color scheme association kinds.

The org.jvnet.substance.api.ColorSchemeAssociationKind is the base class for core and custom color scheme association kinds. Where is this class used?

  • The first usage is in the skin definition. The main SubstanceSkin APIs allow associating different color schemes with different visual areas of Swing controls.
  • The specific UI delegates query the component skin for the color schemes that match the relevant visual areas.

Let’s go back to the JCheckBox icon example above. How do we use the color scheme association kinds to specify three different color schemes for painting this checkmark icon?

As detailed in the skin documentation, each skin has a number of color scheme bundles. This means that two checkboxes with the same model state (selected in out case) can have different visuals, depending on the decoration areas they reside in. In the definition of the specific color scheme bundle, you can specify different color schemes for different component states. This means that a selected checkbox can use colors different from those of a rollover selected checkbox.

In our case, we want to specify different color schemes for different visual areas of selected checkboxes in the default decoration area. The relevant method is the org.jvnet.substance.api.SubstanceColorSchemeBundle is:

registerColorScheme(SubstanceColorScheme scheme, ColorSchemeAssociationKind associationKind, ComponentState... states)

  • The inner fill is specified by the ColorSchemeAssociationKind.FILL.
  • The border is specified by the ColorSchemeAssociationKind.BORDER.
  • The mark is specified by the ColorSchemeAssociationKind.MARK.

Going back once again to the original image:

Here is the outline of the relevant configuration code:

SubstanceColorScheme activeScheme = ...;
SubstanceColorScheme defaultScheme = ...;
SubstanceColorScheme disabledScheme = ...;

SubstanceColorSchemeBundle defaultBundle = new SubstanceColorSchemeBundle(
activeScheme, defaultScheme, disabledScheme);

SubstanceColorScheme selectedBorderScheme = …;
defaultBundle.registerColorScheme(selectedBorderScheme,
ColorSchemeAssociationKind.BORDER, ComponentState.SELECTED);

SubstanceColorScheme selectedMarkScheme = …;
defaultBundle.registerColorScheme(selectedMarkScheme,
ColorSchemeAssociationKind.MARK, ComponentState.SELECTED);

Note that there is no explicit usage of the ColorSchemeAssociationKind.FILL value. This illustrates the fallback mechanism. In this particular case, the second parameter to the SubstanceColorSchemeBundle constructor is used as the fallback color scheme for inner fills under all component states. The fallback mechanism also extends to the other color scheme association kinds.

Here is the constructor signature of the ColorSchemeAssociationKind:

public ColorSchemeAssociationKind(String name, ColorSchemeAssociationKind fallback)

The second parameter specifies what should happen when the color scheme bundle definition does not have an explicitly registered color scheme for the specific color scheme association kind under the specific component state.

For example, the ColorSchemeAssociationKind.MARK has the ColorSchemeAssociationKind.BORDER as its fallback. This means that if you want to use the same color scheme for painting both borders and marks, you need to only call the SubstanceColorSchemeBundle.registerColorScheme API with the ColorSchemeAssociationKind.BORDER value.

The registered associations are used by the Substance UI delegates during the component painting. Specifically for the checkbox, the UI delegate queries the three relevant association kinds (ColorSchemeAssociationKind.FILL, ColorSchemeAssociationKind.BORDER and ColorSchemeAssociationKind.MARK) and uses the relevant painters (gradient and border) to paint the matching visual areas.

Applications that want to provide custom skinning of their UIs can use the following two supported APIs in order to get the relevant color schemes.

First, use the following API in org.jvnet.substance.SubstanceLookAndFeel class to obtain the skin that should be used for painting your component:

public static SubstanceSkin getCurrentSkin(Component c)

Then, use the following API in the obtained org.jvnet.substance.api.SubstanceSkin class to get the color scheme for the relevant visual area:

public SubstanceColorScheme getColorScheme(Component comp, ColorSchemeAssociationKind associationKind, ComponentState componentState)

Note that the second method should always return non-null value, using the fallback mechanism discussed above to return the matching color scheme.

The development of the next 5.2 version of Substance (code-named Quebec) is wrapping up. You’re more than welcome to take the latest 5.2dev binary drops for a spin. The release candidate is planned for May 11, with the final release scheduled for May 25.