org.pushingpixels.substance.api.SubstanceColorSchemeBundle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of substance Show documentation
Show all versions of substance Show documentation
A fork of @kirilcool's substance project
/*
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Substance Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.substance.api;
import java.awt.Component;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.pushingpixels.substance.internal.colorscheme.BlendBiColorScheme;
/**
* Color scheme bundle. Defines the visual appearance of a single decoration
* area of a skin.
*
* @author Kirill Grouchnikov
* @see DecorationAreaType
* @see ColorSchemeAssociationKind
* @see SubstanceSkin
*/
public class SubstanceColorSchemeBundle {
/**
* The active color scheme of this bundle.
*/
protected SubstanceColorScheme activeColorScheme;
/**
* The enabled color scheme of this bundle.
*/
protected SubstanceColorScheme enabledColorScheme;
/**
* The disabled color scheme of this bundle.
*/
protected SubstanceColorScheme disabledColorScheme;
/**
* Maps from component state to the alpha channel applied on color scheme.
* This map doesn't have to contain entries for all {@link ComponentState}
* instances.
*/
protected Map stateAlphaMap;
/**
* Maps from component state to the alpha channel applied on highlight color
* scheme. This map doesn't have to contain entries for all
* {@link ComponentState} instances.
*/
protected Map stateHighlightSchemeAlphaMap;
/**
* If there is no explicitly registered color scheme for pressed component
* state, this field will contain a synthesized color scheme for a pressed
* state.
*/
protected SubstanceColorScheme pressedScheme;
/**
* If there is no explicitly registered color scheme for the disabled
* selected component state, this field will contain a synthesized color
* scheme for the disabled selected state.
*/
protected SubstanceColorScheme disabledSelectedScheme;
/**
* If there is no explicitly registered color scheme for the selected
* component state, this field will contain a synthesized color scheme for
* the selected state.
*/
protected SubstanceColorScheme selectedScheme;
/**
* If there is no explicitly registered color scheme for the rollover
* selected component state, this field will contain a synthesized color
* scheme for the rollover selected state.
*/
protected SubstanceColorScheme rolloverSelectedScheme;
/**
* Maps from color scheme association kinds to the map of color schemes.
* Different visual parts of controls in the specific decoration are can be
* painted with different color schemes. For example, a rollover button can
* use a light orange scheme for the gradient fill and a dark gray scheme
* for the border. In this case, this map will have:
*
*
* - An entry with key {@link ColorSchemeAssociationKind#FILL}. This entry
* has a map entry with key {@link ComponentState#SELECTED} and value that
* points to the light orange scheme.
* - An entry with key {@link ColorSchemeAssociationKind#BORDER}. This
* entry has a map entry with key {@link ComponentState#SELECTED} and value
* that points to the dark gray scheme.
*
*/
protected Map> colorSchemeMap;
protected Map> bestFillMap;
/**
* Creates a new color scheme bundle.
*
* @param activeColorScheme
* The active color scheme of this bundle.
* @param enabledColorScheme
* The enabled color scheme of this bundle.
* @param disabledColorScheme
* The disabled color scheme of this bundle.
*/
public SubstanceColorSchemeBundle(SubstanceColorScheme activeColorScheme,
SubstanceColorScheme enabledColorScheme,
SubstanceColorScheme disabledColorScheme) {
this.activeColorScheme = activeColorScheme;
this.enabledColorScheme = enabledColorScheme;
this.disabledColorScheme = disabledColorScheme;
this.stateAlphaMap = new HashMap();
// ComponentState.class);
this.stateHighlightSchemeAlphaMap = new HashMap();
// ComponentState.class);
this.colorSchemeMap = new HashMap>();
for (ColorSchemeAssociationKind associationKind : ColorSchemeAssociationKind
.values()) {
this.colorSchemeMap.put(associationKind,
new HashMap());
}
this.bestFillMap = new HashMap>();
for (ColorSchemeAssociationKind associationKind : ColorSchemeAssociationKind
.values()) {
this.bestFillMap.put(associationKind,
new HashMap());
}
}
/**
* Registers a color scheme for the specific component state.
*
* @param stateColorScheme
* Color scheme for the specified component state.
* @param alpha
* Alpha channel for the color scheme.
* @param states
* Component states.
*/
public void registerColorScheme(SubstanceColorScheme stateColorScheme,
float alpha, ComponentState... states) {
if (states != null) {
for (ComponentState state : states) {
this.colorSchemeMap.get(ColorSchemeAssociationKind.FILL).put(
state, stateColorScheme);
this.stateAlphaMap.put(state, alpha);
}
}
}
/**
* Registers a color scheme for the specific component state.
*
* @param stateColorScheme
* Color scheme for the specified component state.
* @param states
* Component states.
*/
public void registerColorScheme(SubstanceColorScheme stateColorScheme,
ComponentState... states) {
this.registerColorScheme(stateColorScheme, 1.0f, states);
}
/**
* Registers a highlight color scheme for the specific component state if
* the component state is not null
, or a global highlight color
* scheme otherwise.
*
* @param stateHighlightScheme
* Highlight color scheme for the specified component state.
* @param states
* Component states. If null
, the specified color
* scheme will be applied for all states left unspecified.
*/
public void registerHighlightColorScheme(
SubstanceColorScheme stateHighlightScheme, ComponentState... states) {
if ((states == null) || (states.length == 0)) {
for (ComponentState state : ComponentState.getAllStates()) {
if (this.colorSchemeMap.get(
ColorSchemeAssociationKind.HIGHLIGHT)
.containsKey(state))
continue;
if (state.isDisabled())
continue;
if (state == ComponentState.ENABLED)
continue;
// this.stateHighlightColorSchemeMap.put(state,
// stateHighlightScheme);
this.colorSchemeMap.get(ColorSchemeAssociationKind.HIGHLIGHT)
.put(state, stateHighlightScheme);
}
} else {
for (ComponentState state : states) {
this.colorSchemeMap.get(ColorSchemeAssociationKind.HIGHLIGHT)
.put(state, stateHighlightScheme);
}
}
}
/**
* Registers a highlight color scheme for the specific component state if
* the component state is not null
, or a global highlight color
* scheme otherwise.
*
* @param highlightScheme
* Highlight color scheme for the specified component states.
* @param alpha
* Alpha channel for the highlight color scheme.
* @param states
* Component states. If null
, the specified color
* scheme will be applied for all states left unspecified.
*/
public void registerHighlightColorScheme(
SubstanceColorScheme highlightScheme, float alpha,
ComponentState... states) {
if (highlightScheme == null) {
throw new IllegalArgumentException("Cannot pass null color scheme");
}
if ((states == null) || (states.length == 0)) {
for (ComponentState state : ComponentState.getAllStates()) {
if (state.isDisabled())
continue;
if (state == ComponentState.ENABLED)
continue;
if (!this.colorSchemeMap.get(
ColorSchemeAssociationKind.HIGHLIGHT)
.containsKey(state))
this.colorSchemeMap.get(
ColorSchemeAssociationKind.HIGHLIGHT).put(state,
highlightScheme);
if (!this.stateHighlightSchemeAlphaMap.containsKey(state))
this.stateHighlightSchemeAlphaMap.put(state, alpha);
}
} else {
for (ComponentState state : states) {
this.colorSchemeMap.get(ColorSchemeAssociationKind.HIGHLIGHT)
.put(state, highlightScheme);
this.stateHighlightSchemeAlphaMap.put(state, alpha);
}
}
}
/**
* Returns the color scheme of the specified component in the specified
* component state.
*
* @param componentState
* Component state.
* @return The color scheme of the component in the specified component
* state.
*/
public SubstanceColorScheme getColorScheme(ComponentState componentState) {
SubstanceColorScheme registered = this.colorSchemeMap.get(
ColorSchemeAssociationKind.FILL).get(componentState);
if (registered != null)
return registered;
// if (componentState.isActive()) {
// for now look for the best fit only on active states
Map bestFitForFill = this.bestFillMap
.get(ColorSchemeAssociationKind.FILL);
if (!bestFitForFill.containsKey(componentState)) {
Collection registeredStates = this.colorSchemeMap
.get(ColorSchemeAssociationKind.FILL).keySet();
bestFitForFill.put(componentState, componentState
.bestFit(registeredStates));
}
ComponentState bestFit = bestFitForFill.get(componentState);
if (bestFit != null) {
registered = this.colorSchemeMap.get(
ColorSchemeAssociationKind.FILL).get(bestFit);
if (registered != null)
return registered;
}
// }
if (componentState.isFacetActive(ComponentStateFacet.PRESS)) {
if (this.pressedScheme == null) {
this.pressedScheme = this.activeColorScheme.shade(0.2)
.saturate(0.1);
}
return this.pressedScheme;
}
if (componentState == ComponentState.DISABLED_SELECTED) {
if (this.disabledSelectedScheme == null) {
this.disabledSelectedScheme = new BlendBiColorScheme(
this.activeColorScheme, this.disabledColorScheme, 0.25);
}
return this.disabledSelectedScheme;
}
if (componentState == ComponentState.SELECTED) {
if (this.selectedScheme == null) {
this.selectedScheme = this.activeColorScheme.saturate(0.2);
}
return this.selectedScheme;
}
if (componentState == ComponentState.ROLLOVER_SELECTED) {
if (this.rolloverSelectedScheme == null) {
this.rolloverSelectedScheme = this.activeColorScheme.tint(0.1)
.saturate(0.1);
}
return this.rolloverSelectedScheme;
}
ComponentState hardFallback = componentState.getHardFallback();
if (hardFallback != null)
return this.getColorScheme(hardFallback);
if (componentState == ComponentState.ENABLED)
return this.enabledColorScheme;
if (componentState.isDisabled())
return this.disabledColorScheme;
return this.activeColorScheme;
}
/**
* Returns the alpha channel of the highlight color scheme of the component.
*
* @param comp
* Component.
* @param componentState
* Component state.
* @return Highlight color scheme alpha channel.
*/
public float getHighlightAlpha(Component comp, ComponentState componentState) {
Float registered = this.stateHighlightSchemeAlphaMap
.get(componentState);
if (registered != null)
return registered;
return -1.0f;
}
/**
* Returns the alpha channel of the color scheme of the component.
*
* @param comp
* Component.
* @param componentState
* Component state.
* @return Color scheme alpha channel.
*/
public float getAlpha(Component comp, ComponentState componentState) {
Float registered = this.stateAlphaMap.get(componentState);
if (registered != null)
return registered;
return -1.0f;
}
/**
* Returns the active color scheme of this bundle.
*
* @return The active color scheme of this bundle.
*/
public SubstanceColorScheme getActiveColorScheme() {
return activeColorScheme;
}
/**
* Returns the enabled color scheme of this bundle.
*
* @return The enabled color scheme of this bundle.
*/
public SubstanceColorScheme getEnabledColorScheme() {
return enabledColorScheme;
}
/**
* Returns the disabled color scheme of this bundle.
*
* @return The disabled color scheme of this bundle.
*/
public SubstanceColorScheme getDisabledColorScheme() {
return disabledColorScheme;
}
/**
* Registers the color scheme to be used for the specified visual area of
* controls under the specified states. For example, if the light orange
* scheme has to be used for gradient fill of rollover selected and rollover
* controls, the parameters would be:
*
*
* scheme
=light orange scheme
* -
*
associationKind
={@link ColorSchemeAssociationKind#FILL}
* -
*
states
={@link ComponentState#ROLLOVER_SELECTED},
* {@link ComponentState#ROLLOVER_UNSELECTED}
*
*
* @param scheme
* Color scheme.
* @param associationKind
* Color scheme association kind that specifies the visual areas
* of controls to be painted with this color scheme.
* @param states
* Component states that further restrict the usage of the
* specified color scheme.
* @since version 5.1
*/
public void registerColorScheme(SubstanceColorScheme scheme,
ColorSchemeAssociationKind associationKind,
ComponentState... states) {
if (scheme == null) {
throw new IllegalArgumentException("Cannot pass null color scheme");
}
if ((states == null) || (states.length == 0)) {
for (ComponentState state : ComponentState.getAllStates()) {
if (this.colorSchemeMap.get(associationKind).containsKey(state))
continue;
this.colorSchemeMap.get(associationKind).put(state, scheme);
}
} else {
for (ComponentState state : states) {
this.colorSchemeMap.get(associationKind).put(state, scheme);
}
}
}
/**
* Returns the color scheme to be used for painting the specified visual
* area of the component under the specified component state.
*
* @param associationKind
* Color scheme association kind.
* @param componentState
* Component state.
* @return Color scheme to be used for painting the specified visual area of
* the component under the specified component state.
* @see #registerColorScheme(SubstanceColorScheme, ComponentState...)
* @since version 5.1
*/
public SubstanceColorScheme getColorScheme(
ColorSchemeAssociationKind associationKind,
ComponentState componentState) {
if (associationKind == ColorSchemeAssociationKind.FILL)
return this.getColorScheme(componentState);
SubstanceColorScheme registered = this.colorSchemeMap.get(
associationKind).get(componentState);
if (registered != null)
return registered;
// if (componentState.isActive()) {
// for now look for the best fit only on active states
Map bestFitForState = this.bestFillMap
.get(associationKind);
if (!bestFitForState.containsKey(componentState)) {
Collection registeredStates = this.colorSchemeMap
.get(associationKind).keySet();
bestFitForState.put(componentState, componentState
.bestFit(registeredStates));
}
ComponentState bestFit = bestFitForState.get(componentState);
if (bestFit != null) {
registered = this.colorSchemeMap.get(associationKind).get(bestFit);
if (registered != null)
return registered;
}
// }
ColorSchemeAssociationKind fallback = associationKind.getFallback();
if (fallback == null)
return null;
return getColorScheme(fallback, componentState);
}
/**
* Creates a new color scheme bundle that has the same settings as this
* color scheme bundle with the addition of applying the specified color
* scheme transformation on all the relevant color schemes
*
* @param transform
* Color scheme transformation.
* @return The new color scheme bundle.
*/
SubstanceColorSchemeBundle transform(ColorSchemeTransform transform) {
// transform the basic schemes
SubstanceColorSchemeBundle result = new SubstanceColorSchemeBundle(
transform.transform(this.activeColorScheme), transform
.transform(this.enabledColorScheme), transform
.transform(this.disabledColorScheme));
for (Map.Entry> entry : this.colorSchemeMap
.entrySet()) {
for (Map.Entry subEntry : entry
.getValue().entrySet()) {
result.colorSchemeMap.get(entry.getKey()).put(
subEntry.getKey(),
transform.transform(subEntry.getValue()));
}
}
// alphas are the same
if (this.stateAlphaMap != null) {
result.stateAlphaMap = new HashMap(
this.stateAlphaMap);
}
// highlight alphas are the same
if (this.stateHighlightSchemeAlphaMap != null) {
result.stateHighlightSchemeAlphaMap = new HashMap(
this.stateHighlightSchemeAlphaMap);
}
return result;
}
/**
* Returns the set of all component states that have non-trivial alpha
* associated with them. Non-trivial alpha is a value that is strictly less
* than 1.0.
*
* @return All component states that have associated non-trivial alpha
* values.
*/
Set getStatesWithAlpha() {
Set result = new HashSet();// EnumSet.noneOf(ComponentState.class);
for (Map.Entry alphaEntry : this.stateAlphaMap
.entrySet()) {
if (alphaEntry.getValue() < 1.0f) {
result.add(alphaEntry.getKey());
}
}
return result;
}
}