org.pushingpixels.substance.api
Class ComponentState

java.lang.Object
  extended by org.pushingpixels.substance.api.ComponentState

public final class ComponentState
extends java.lang.Object

Instances of this class correspond to states of Swing core and custom controls. This class provides a number of predefined static instances to cover most action-based controls such as buttons, check boxes and menu items. In addition, application code can define custom component states that create fine grained mapping between arbitrary states of controls and specific color scheme bundles in custom skins.

Each component state is defined by two arrays of component state facets (available in ComponentStateFacet class). The first array specifies the facets that are on, and the second array specifies the facets that are off. For example, when a selected toggle button is pressed, it transitions to PRESSED_SELECTED state. This state has ComponentStateFacet.ENABLE, ComponentStateFacet.SELECTION and ComponentStateFacet.PRESS as its on facets. If a selected toggle button is disabled, it has ComponentStateFacet.SELECTION in its on facets and ComponentStateFacet.ENABLE in its off facets.

The ComponentStateFacet class defines a number of core facets. The ComponentStateFacet.ENABLE facet is universal - it is relevant for all Swing controls. Other facets apply to a wider range of controls. For example, ComponentStateFacet.ROLLOVER facet applies to all controls that can show rollover effects - including buttons, menu items, comboboxes, sliders, scrollbars and many more. Some facets apply to a very narrow range of controls. For exaple, ComponentStateFacet.EDITABLE is only relevant for editable controls, such as text components, editable comboboxes or spinners.

The static instances of ComponentState defined in this class do not aim to cover all possible combinations of on and off facets. In addition to making this class to unwieldy, it is not possible to do since application code can define its own facets. Instead, Substance provides three ways to fine-tune the mapping between the component states and the color schemes used to paint the components.

  1. When the skin is queried for the color scheme that matches the specific component state - let's say PRESSED_SELECTED - the skinning layer first looks for the exact state (as passed to SubstanceColorSchemeBundle.registerColorScheme(SubstanceColorScheme, ColorSchemeAssociationKind, ComponentState...) or similar APIs). If the exact match is found, it is used. If there is no exact match, the skinning layer will look at all color schemes registered for the specific color scheme association kind in the matching color scheme bundle. The decision is made based on how "close" the registered component state is to the component state of the currently painted component. For example, PRESSED_SELECTED is a better match for PRESSED_UNSELECTED than ROLLOVER_SELECTED - since the ComponentStateFacet.PRESS has more weight than the ComponentStateFacet.ROLLOVER in the decision process. The skinning layer will choose the "closest" registered component state that is sufficiently close. For example, DISABLED_SELECTED will never be chosen for SELECTED, even if there are no other registered component states. This way the application code can register a few color schemes in the specific bundle, and have all other states "fall back" to the smaller subset of states.
  2. Facets such as ComponentStateFacet.DETERMINATE or ComponentStateFacet.EDITABLE are relevant only for a small subset of controls. In order to simplify the API signature of ComponentState, these facets are not part of any of the predefined static states in this class. Instead, they are used internally in the matching UI delegates (such as for progress bar or text components) to find the best match among all the registered states of the current skin. The specific skin can define its own ComponentState instances that use these facets. For example, NebulaSkin defines a number of component states that use the ComponentStateFacet.DETERMINATE facet, and maps the matching color schemes. At runtime, the procedure described in the previous item will match the state of the specific progress bar to the states defined in this skin, and use the matching color schemes.
  3. Custom application components may have facets that do not directly map to the core facets defined in the ComponentStateFacet class. In this case, the application code can create its own facet instances, and its own component states that use those facets in the on and off lists. Part of the custom code will be in the UI delegates that compute the current state of the custom component using the new facets. Other part of the custom code will be in the skin definition that maps the component states defined with the new facets to the specific color schemes.

Note that you do not have to create explicit dependency between custom component states used in the skin definition and custom component states used in the painting routines (in the UI delegates). In fact, the custom component states defined in the Substance UI delegate for progress bar are not accessible to the application code. The recommended way to separate the skin definition from the model lookups in the painting is:

Note that the matching algorithm only looks at the facets in the on and off lists, and ignores the component state name. This allows you to create a broad component state in your skin, and a number of narrow component states during the painting - and have the Substance skinning layer find the best match.

When the matching algorithm cannot find a sufficiently close match, the skinning layer will fall back on one of the three base color schemes passed to the SubstanceColorSchemeBundle.SubstanceColorSchemeBundle(SubstanceColorScheme, SubstanceColorScheme, SubstanceColorScheme) constructor. States with ComponentStateFacet.ENABLE in their off list will fall back to the disabled color scheme. The ENABLED will fall back to the enabled color scheme. The rest of the states will fall back to the active color scheme. To change the fallback behavior pass a non-null fallback color scheme to the ComponentState(String, ComponentState, ComponentStateFacet[], ComponentStateFacet[]) constructor as the second parameter.


Field Summary
static ComponentState ARMED
          Armed.
static ComponentState DEFAULT
          Default.
static ComponentState DISABLED_DEFAULT
          Disabled default.
static ComponentState DISABLED_SELECTED
          Disabled selected.
static ComponentState DISABLED_UNSELECTED
          Disabled and not selected.
static ComponentState ENABLED
          Enabled state.
static ComponentState PRESSED_SELECTED
          Pressed selected.
static ComponentState PRESSED_UNSELECTED
          Pressed and not selected.
static ComponentState ROLLOVER_ARMED
          Armed and rolled over.
static ComponentState ROLLOVER_SELECTED
          Selected and rolled over.
static ComponentState ROLLOVER_UNSELECTED
          Not selected and rolled over.
static ComponentState SELECTED
          Selected.
 
Constructor Summary
ComponentState(java.lang.String name, ComponentState hardFallback, ComponentStateFacet[] facetsOn, ComponentStateFacet[] facetsOff)
          Creates a new component state.
ComponentState(java.lang.String name, ComponentStateFacet[] facetsOn, ComponentStateFacet[] facetsOff)
          Creates a new component state.
 
Method Summary
 ComponentState bestFit(java.util.Collection<ComponentState> states)
           
 boolean equals(java.lang.Object obj)
           
static ComponentState[] getActiveStates()
          Returns all active component states.
static java.util.Set<ComponentState> getAllStates()
          Returns all component states.
 ComponentState getHardFallback()
           
static ComponentState getState(javax.swing.AbstractButton button)
          Returns the state of the specified button.
static ComponentState getState(boolean isEnabled, boolean isRollover, boolean isSelected)
          Returns the component state that matches the specified parameters.
static ComponentState getState(javax.swing.ButtonModel model, javax.swing.JComponent component)
          Retrieves component state based on the button model (required parameter) and component itself (optional parameter).
static ComponentState getState(javax.swing.ButtonModel model, javax.swing.JComponent component, boolean toIgnoreSelection)
          Retrieves component state based on the button model (required parameter) and button itself (optional parameter).
 int hashCode()
           
 boolean isActive()
           
 boolean isDisabled()
          Checks whether this state is disabled.
 boolean isFacetActive(ComponentStateFacet stateFacet)
          Returns indication whether this component state is "active" under the specified facet.
 java.lang.String toString()
           
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

DISABLED_DEFAULT

public static final ComponentState DISABLED_DEFAULT
Disabled default. Used for disabled buttons that have been marked as default with JRootPane.setDefaultButton(JButton) API.


DEFAULT

public static final ComponentState DEFAULT
Default. Used for enabled buttons that have been marked as default with JRootPane.setDefaultButton(JButton) API.


DISABLED_SELECTED

public static final ComponentState DISABLED_SELECTED
Disabled selected.


DISABLED_UNSELECTED

public static final ComponentState DISABLED_UNSELECTED
Disabled and not selected.


PRESSED_SELECTED

public static final ComponentState PRESSED_SELECTED
Pressed selected.


PRESSED_UNSELECTED

public static final ComponentState PRESSED_UNSELECTED
Pressed and not selected.


SELECTED

public static final ComponentState SELECTED
Selected.


ROLLOVER_SELECTED

public static final ComponentState ROLLOVER_SELECTED
Selected and rolled over.


ARMED

public static final ComponentState ARMED
Armed.


ROLLOVER_ARMED

public static final ComponentState ROLLOVER_ARMED
Armed and rolled over.


ROLLOVER_UNSELECTED

public static final ComponentState ROLLOVER_UNSELECTED
Not selected and rolled over.


ENABLED

public static final ComponentState ENABLED
Enabled state.

Constructor Detail

ComponentState

public ComponentState(java.lang.String name,
                      ComponentStateFacet[] facetsOn,
                      ComponentStateFacet[] facetsOff)
Creates a new component state.

Parameters:
name - Component state name. Does not have to be unique. The name is only used in the toString().
facetsOn - Indicates that are turned on for this state. For example, ROLLOVER_SELECTED should pass both ComponentStateFacet.ROLLOVER and ComponentStateFacet.SELECTION.
facetsOff - Indicates that are turned on for this state. For example, DISABLED_UNSELECTED should pass both ComponentStateFacet.ENABLE and ComponentStateFacet.SELECTION.

ComponentState

public ComponentState(java.lang.String name,
                      ComponentState hardFallback,
                      ComponentStateFacet[] facetsOn,
                      ComponentStateFacet[] facetsOff)
Creates a new component state.

Parameters:
name - Component state name. Does not have to be unique. The name is only used in the toString().
hardFallback - The fallback state that will be used in SubstanceColorSchemeBundle.getColorScheme(ColorSchemeAssociationKind, ComponentState) in case bestFit(Collection) returns null
facetsOn - Indicates that are turned on for this state. For example, ROLLOVER_SELECTED should pass both ComponentStateFacet.ROLLOVER and ComponentStateFacet.SELECTION.
facetsOff - Indicates that are turned on for this state. For example, DISABLED_UNSELECTED should pass both ComponentStateFacet.ENABLE and ComponentStateFacet.SELECTION.
Method Detail

toString

public java.lang.String toString()
Overrides:
toString in class java.lang.Object

isFacetActive

public boolean isFacetActive(ComponentStateFacet stateFacet)
Returns indication whether this component state is "active" under the specified facet. For example, ROLLOVER_SELECTED will return true for both ComponentStateFacet.ROLLOVER and ComponentStateFacet.SELECTION.

Parameters:
stateFacet - State facet.
Returns:
true if this component state is "active" under the specified facet (for example, ROLLOVER_SELECTED will return true for both ComponentStateFacet.ROLLOVER and ComponentStateFacet.SELECTION), false otherwise.

isDisabled

public boolean isDisabled()
Checks whether this state is disabled. A disabled state has ComponentStateFacet.ENABLE facet in its off set.

Returns:
true if this state is disabled, false otherwise.

getActiveStates

public static ComponentState[] getActiveStates()
Returns all active component states.

Returns:
All active component states.

getAllStates

public static java.util.Set<ComponentState> getAllStates()
Returns all component states.

Returns:
All component states

isActive

public boolean isActive()

getState

public static ComponentState getState(javax.swing.ButtonModel model,
                                      javax.swing.JComponent component)
Retrieves component state based on the button model (required parameter) and component itself (optional parameter).

Parameters:
model - Button model (required).
component - Component (optional).
Returns:
The matching component state.

getState

public static ComponentState getState(javax.swing.AbstractButton button)
Returns the state of the specified button.

Parameters:
button - Button.
Returns:
The state of the specified button.

getState

public static ComponentState getState(javax.swing.ButtonModel model,
                                      javax.swing.JComponent component,
                                      boolean toIgnoreSelection)
Retrieves component state based on the button model (required parameter) and button itself (optional parameter).

Parameters:
model - Button model (required).
component - Component (optional).
toIgnoreSelection - If true, the ButtonModel.isSelected() will not be checked. This can be used for tracking transitions on menu items that use armed state instead, when we don't want to use different rollover themes for selected and unselected checkbox and radio button menu items (to preserve consistent visual appearence of highlights).
Returns:
The matching component state.

getState

public static ComponentState getState(boolean isEnabled,
                                      boolean isRollover,
                                      boolean isSelected)
Returns the component state that matches the specified parameters.

Parameters:
isEnabled - Enabled flag.
isRollover - Rollover flag.
isSelected - Selected flag.
Returns:
The component state that matches the specified parameters.

bestFit

public ComponentState bestFit(java.util.Collection<ComponentState> states)

getHardFallback

public ComponentState getHardFallback()

hashCode

public int hashCode()
Overrides:
hashCode in class java.lang.Object

equals

public boolean equals(java.lang.Object obj)
Overrides:
equals in class java.lang.Object