mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 22:10:54 +03:00
Button: hover and pressed background colors are now derived from actual button background color (issue #21)
This commit is contained in:
@@ -10,6 +10,8 @@ FlatLaf Change Log
|
|||||||
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
|
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
|
||||||
an outside focus border (e.g. IntelliJ and Darcula themes). (issues #20 and
|
an outside focus border (e.g. IntelliJ and Darcula themes). (issues #20 and
|
||||||
#17)
|
#17)
|
||||||
|
- Button: Hover and pressed background colors are now derived from actual button
|
||||||
|
background color. (issue #21)
|
||||||
|
|
||||||
|
|
||||||
## 0.16
|
## 0.16
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import javax.swing.plaf.DimensionUIResource;
|
|||||||
import javax.swing.plaf.InsetsUIResource;
|
import javax.swing.plaf.InsetsUIResource;
|
||||||
import com.formdev.flatlaf.ui.FlatEmptyBorder;
|
import com.formdev.flatlaf.ui.FlatEmptyBorder;
|
||||||
import com.formdev.flatlaf.ui.FlatLineBorder;
|
import com.formdev.flatlaf.ui.FlatLineBorder;
|
||||||
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
|
import com.formdev.flatlaf.util.DerivedColor;
|
||||||
import com.formdev.flatlaf.util.ScaledNumber;
|
import com.formdev.flatlaf.util.ScaledNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,7 +103,11 @@ class UIDefaultsLoader
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
String value = resolveValue( properties, (String) e.getValue() );
|
String value = resolveValue( properties, (String) e.getValue() );
|
||||||
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
|
try {
|
||||||
|
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
|
||||||
|
} catch( RuntimeException ex ) {
|
||||||
|
logParseError( key, value, ex );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// override UI defaults with globals
|
// override UI defaults with globals
|
||||||
@@ -122,13 +128,22 @@ class UIDefaultsLoader
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
String value = resolveValue( properties, (String) e.getValue() );
|
String value = resolveValue( properties, (String) e.getValue() );
|
||||||
defaults.put( key, parseValue( key, value, resolver ) );
|
try {
|
||||||
|
defaults.put( key, parseValue( key, value, resolver ) );
|
||||||
|
} catch( RuntimeException ex ) {
|
||||||
|
logParseError( key, value, ex );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void logParseError( String key, String value, RuntimeException ex ) {
|
||||||
|
System.err.println( "Failed to parse: '" + key + '=' + value + '\'' );
|
||||||
|
System.err.println( " " + ex.getMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
private static String resolveValue( Properties properties, String value ) {
|
private static String resolveValue( Properties properties, String value ) {
|
||||||
if( !value.startsWith( VARIABLE_PREFIX ) )
|
if( !value.startsWith( VARIABLE_PREFIX ) )
|
||||||
return value;
|
return value;
|
||||||
@@ -147,8 +162,7 @@ class UIDefaultsLoader
|
|||||||
if( optional )
|
if( optional )
|
||||||
return "null";
|
return "null";
|
||||||
|
|
||||||
System.err.println( "variable or reference '" + value + "' not found" );
|
throw new IllegalArgumentException( "variable or reference '" + value + "' not found" );
|
||||||
throw new IllegalArgumentException( value );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveValue( properties, newValue );
|
return resolveValue( properties, newValue );
|
||||||
@@ -264,8 +278,7 @@ class UIDefaultsLoader
|
|||||||
Integer.parseInt( numbers.get( 2 ) ),
|
Integer.parseInt( numbers.get( 2 ) ),
|
||||||
Integer.parseInt( numbers.get( 3 ) ) );
|
Integer.parseInt( numbers.get( 3 ) ) );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
System.err.println( "invalid insets '" + value + "'" );
|
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,12 +289,14 @@ class UIDefaultsLoader
|
|||||||
Integer.parseInt( numbers.get( 0 ) ),
|
Integer.parseInt( numbers.get( 0 ) ),
|
||||||
Integer.parseInt( numbers.get( 1 ) ) );
|
Integer.parseInt( numbers.get( 1 ) ) );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
System.err.println( "invalid size '" + value + "'" );
|
throw new IllegalArgumentException( "invalid size '" + value + "'" );
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ColorUIResource parseColor( String value, boolean reportError ) {
|
private static ColorUIResource parseColor( String value, boolean reportError ) {
|
||||||
|
if( value.endsWith( ")" ) )
|
||||||
|
return parseColorFunctions( value, reportError );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int rgb = Integer.parseInt( value, 16 );
|
int rgb = Integer.parseInt( value, 16 );
|
||||||
if( value.length() == 6 )
|
if( value.length() == 6 )
|
||||||
@@ -292,23 +307,78 @@ class UIDefaultsLoader
|
|||||||
if( reportError )
|
if( reportError )
|
||||||
throw new NumberFormatException( value );
|
throw new NumberFormatException( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
if( reportError ) {
|
if( reportError )
|
||||||
System.err.println( "invalid color '" + value + "'" );
|
throw new IllegalArgumentException( "invalid color '" + value + "'" );
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
// not a color --> ignore
|
// not a color --> ignore
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ColorUIResource parseColorFunctions( String value, boolean reportError ) {
|
||||||
|
int paramsStart = value.indexOf( '(' );
|
||||||
|
if( paramsStart < 0 ) {
|
||||||
|
if( reportError )
|
||||||
|
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String function = value.substring( 0, paramsStart ).trim();
|
||||||
|
List<String> params = split( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
||||||
|
if( params.isEmpty() )
|
||||||
|
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||||
|
|
||||||
|
switch( function ) {
|
||||||
|
case "lighten": return parseColorLightenOrDarken( true, params, reportError );
|
||||||
|
case "darken": return parseColorLightenOrDarken( false, params, reportError );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syntax: lighten(amount[,options]) or darken(amount[,options])
|
||||||
|
* - amount: percentage 0-100%
|
||||||
|
* - options: [relative] [autoInverse]
|
||||||
|
*/
|
||||||
|
private static ColorUIResource parseColorLightenOrDarken( boolean lighten, List<String> params, boolean reportError ) {
|
||||||
|
int amount = parsePercentage( params.get( 0 ) );
|
||||||
|
boolean relative = false;
|
||||||
|
boolean autoInverse = false;
|
||||||
|
|
||||||
|
if( params.size() >= 2 ) {
|
||||||
|
String options = params.get( 1 );
|
||||||
|
relative = options.contains( "relative" );
|
||||||
|
autoInverse = options.contains( "autoInverse" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DerivedColor( lighten
|
||||||
|
? new ColorFunctions.Lighten( amount, relative, autoInverse )
|
||||||
|
: new ColorFunctions.Darken( amount, relative, autoInverse ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parsePercentage( String value ) {
|
||||||
|
if( !value.endsWith( "%" ) )
|
||||||
|
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
||||||
|
|
||||||
|
int val;
|
||||||
|
try {
|
||||||
|
val = Integer.parseInt( value.substring( 0, value.length() - 1 ) );
|
||||||
|
} catch( NumberFormatException ex ) {
|
||||||
|
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( val < 0 || val > 100 )
|
||||||
|
throw new IllegalArgumentException( "percentage out of range (0-100%) '" + value + "'" );
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
private static Integer parseInteger( String value, boolean reportError ) {
|
private static Integer parseInteger( String value, boolean reportError ) {
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt( value );
|
return Integer.parseInt( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
if( reportError ) {
|
if( reportError )
|
||||||
System.err.println( "invalid integer '" + value + "'" );
|
throw new NumberFormatException( "invalid integer '" + value + "'" );
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -317,8 +387,7 @@ class UIDefaultsLoader
|
|||||||
try {
|
try {
|
||||||
return new ScaledNumber( Integer.parseInt( value ) );
|
return new ScaledNumber( Integer.parseInt( value ) );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
System.err.println( "invalid integer '" + value + "'" );
|
throw new NumberFormatException( "invalid integer '" + value + "'" );
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,12 +109,13 @@ public class FlatCheckBoxIcon
|
|||||||
paintBorder( g2 );
|
paintBorder( g2 );
|
||||||
|
|
||||||
// paint background
|
// paint background
|
||||||
g2.setColor( FlatButtonUI.buttonStateColor( c,
|
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||||
selected ? selectedBackground : background,
|
selected ? selectedBackground : background,
|
||||||
disabledBackground,
|
disabledBackground,
|
||||||
focusedBackground,
|
focusedBackground,
|
||||||
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
|
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
|
||||||
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ) );
|
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ),
|
||||||
|
background );
|
||||||
paintBackground( g2 );
|
paintBackground( g2 );
|
||||||
|
|
||||||
// paint checkmark
|
// paint checkmark
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.geom.Ellipse2D;
|
|||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Help button icon for {@link javax.swing.JButton}.
|
* Help button icon for {@link javax.swing.JButton}.
|
||||||
@@ -99,12 +100,12 @@ public class FlatHelpButtonIcon
|
|||||||
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
|
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
|
||||||
|
|
||||||
// paint background
|
// paint background
|
||||||
g2.setColor( FlatButtonUI.buttonStateColor( c,
|
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||||
background,
|
background,
|
||||||
disabledBackground,
|
disabledBackground,
|
||||||
focusedBackground,
|
focusedBackground,
|
||||||
hoverBackground,
|
hoverBackground,
|
||||||
pressedBackground ) );
|
pressedBackground ), background );
|
||||||
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
|
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
|
||||||
|
|
||||||
// paint question mark
|
// paint question mark
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ public class FlatButtonUI
|
|||||||
float focusWidth = (border instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
float focusWidth = (border instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||||
float arc = (border instanceof FlatButtonBorder || isToolBarButton( c )) ? scale( (float) this.arc ) : 0;
|
float arc = (border instanceof FlatButtonBorder || isToolBarButton( c )) ? scale( (float) this.arc ) : 0;
|
||||||
|
|
||||||
g2.setColor( background );
|
FlatUIUtils.setColor( g2, background, isDefaultButton(c) ? defaultBackground : c.getBackground() );
|
||||||
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
} finally {
|
} finally {
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import javax.swing.JComponent;
|
|||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ColorUIResource;
|
import javax.swing.plaf.ColorUIResource;
|
||||||
|
import com.formdev.flatlaf.util.DerivedColor;
|
||||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -104,6 +105,12 @@ public class FlatUIUtils
|
|||||||
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
|
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setColor( Graphics g, Color color, Color baseColor ) {
|
||||||
|
if( color instanceof DerivedColor )
|
||||||
|
color = ((DerivedColor)color).derive( baseColor );
|
||||||
|
g.setColor( color );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a round rectangle.
|
* Draws a round rectangle.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions that modify colors.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class ColorFunctions
|
||||||
|
{
|
||||||
|
public static Color applyFunctions( Color color, ColorFunction[] functions ) {
|
||||||
|
float[] hsl = HSLColor.fromRGB( color );
|
||||||
|
float alpha = color.getAlpha() / 255f;
|
||||||
|
|
||||||
|
for( ColorFunction function : functions )
|
||||||
|
function.apply( hsl );
|
||||||
|
|
||||||
|
return HSLColor.toRGB( hsl, alpha );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float clamp( float value ) {
|
||||||
|
return (value < 0)
|
||||||
|
? 0
|
||||||
|
: ((value > 100)
|
||||||
|
? 100
|
||||||
|
: value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface ColorFunction --------------------------------------------
|
||||||
|
|
||||||
|
public interface ColorFunction {
|
||||||
|
void apply( float[] hsl );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class Lighten ------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase the lightness of a color in the HSL color space by an absolute
|
||||||
|
* or relative amount.
|
||||||
|
*/
|
||||||
|
public static class Lighten
|
||||||
|
implements ColorFunction
|
||||||
|
{
|
||||||
|
private final float amount;
|
||||||
|
private final boolean relative;
|
||||||
|
private final boolean autoInverse;
|
||||||
|
|
||||||
|
public Lighten( float amount, boolean relative, boolean autoInverse ) {
|
||||||
|
this.amount = amount;
|
||||||
|
this.relative = relative;
|
||||||
|
this.autoInverse = autoInverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply( float[] hsl ) {
|
||||||
|
float amount2 = autoInverse && shouldInverse( hsl ) ? -amount : amount;
|
||||||
|
hsl[2] = clamp( relative
|
||||||
|
? (hsl[2] * ((100 + amount2) / 100))
|
||||||
|
: (hsl[2] + amount2) );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldInverse( float[] hsl ) {
|
||||||
|
return hsl[2] >= 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class Darken -------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrease the lightness of a color in the HSL color space by an absolute
|
||||||
|
* or relative amount.
|
||||||
|
*/
|
||||||
|
public static class Darken
|
||||||
|
extends Lighten
|
||||||
|
{
|
||||||
|
public Darken( float amount, boolean relative, boolean autoInverse ) {
|
||||||
|
super( -amount, relative, autoInverse );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldInverse( float[] hsl ) {
|
||||||
|
return hsl[2] < 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import javax.swing.plaf.ColorUIResource;
|
||||||
|
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (red) color that acts as a placeholder in UI defaults.
|
||||||
|
* The actual color is derived from another color,
|
||||||
|
* which is modified by the given color functions.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class DerivedColor
|
||||||
|
extends ColorUIResource
|
||||||
|
{
|
||||||
|
private final ColorFunction[] functions;
|
||||||
|
|
||||||
|
public DerivedColor( ColorFunction... functions ) {
|
||||||
|
super( Color.red );
|
||||||
|
this.functions = functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color derive( Color baseColor ) {
|
||||||
|
return ColorFunctions.applyFunctions( baseColor, functions );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,432 @@
|
|||||||
|
/*
|
||||||
|
* From http://tips4java.wordpress.com/2009/07/05/hsl-color/
|
||||||
|
*
|
||||||
|
* License note on http://tips4java.wordpress.com/about/
|
||||||
|
* "You are free to use and/or modify any or all code posted on the
|
||||||
|
* Java Tips Weblog without restriction. A credit in the code comments
|
||||||
|
* would be nice, but not in any way mandatory."
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HSLColor class provides methods to manipulate HSL (Hue, Saturation
|
||||||
|
* Luminance) values to create a corresponding Color object using the RGB
|
||||||
|
* ColorSpace.
|
||||||
|
*
|
||||||
|
* The HUE is the color, the Saturation is the purity of the color (with
|
||||||
|
* respect to grey) and Luminance is the brightness of the color (with respect
|
||||||
|
* to black and white)
|
||||||
|
*
|
||||||
|
* The Hue is specified as an angel between 0 - 360 degrees where red is 0,
|
||||||
|
* green is 120 and blue is 240. In between you have the colors of the rainbow.
|
||||||
|
* Saturation is specified as a percentage between 0 - 100 where 100 is fully
|
||||||
|
* saturated and 0 approaches gray. Luminance is specified as a percentage
|
||||||
|
* between 0 - 100 where 0 is black and 100 is white.
|
||||||
|
*
|
||||||
|
* In particular the HSL color space makes it easier change the Tone or Shade
|
||||||
|
* of a color by adjusting the luminance value.
|
||||||
|
*/
|
||||||
|
public class HSLColor
|
||||||
|
{
|
||||||
|
private final Color rgb;
|
||||||
|
private final float[] hsl;
|
||||||
|
private final float alpha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HSLColor object using an RGB Color object.
|
||||||
|
*
|
||||||
|
* @param rgb the RGB Color object
|
||||||
|
*/
|
||||||
|
public HSLColor(Color rgb)
|
||||||
|
{
|
||||||
|
this.rgb = rgb;
|
||||||
|
hsl = fromRGB( rgb );
|
||||||
|
alpha = rgb.getAlpha() / 255.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HSLColor object using individual HSL values and a default
|
||||||
|
* alpha value of 1.0.
|
||||||
|
*
|
||||||
|
* @param h is the Hue value in degrees between 0 - 360
|
||||||
|
* @param s is the Saturation percentage between 0 - 100
|
||||||
|
* @param l is the Lumanance percentage between 0 - 100
|
||||||
|
*/
|
||||||
|
public HSLColor(float h, float s, float l)
|
||||||
|
{
|
||||||
|
this(h, s, l, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HSLColor object using individual HSL values.
|
||||||
|
*
|
||||||
|
* @param h the Hue value in degrees between 0 - 360
|
||||||
|
* @param s the Saturation percentage between 0 - 100
|
||||||
|
* @param l the Lumanance percentage between 0 - 100
|
||||||
|
* @param alpha the alpha value between 0 - 1
|
||||||
|
*/
|
||||||
|
public HSLColor(float h, float s, float l, float alpha)
|
||||||
|
{
|
||||||
|
hsl = new float[] {h, s, l};
|
||||||
|
this.alpha = alpha;
|
||||||
|
rgb = toRGB(hsl, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HSLColor object using an an array containing the
|
||||||
|
* individual HSL values and with a default alpha value of 1.
|
||||||
|
*
|
||||||
|
* @param hsl array containing HSL values
|
||||||
|
*/
|
||||||
|
public HSLColor(float[] hsl)
|
||||||
|
{
|
||||||
|
this(hsl, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HSLColor object using an an array containing the
|
||||||
|
* individual HSL values.
|
||||||
|
*
|
||||||
|
* @param hsl array containing HSL values
|
||||||
|
* @param alpha the alpha value between 0 - 1
|
||||||
|
*/
|
||||||
|
public HSLColor(float[] hsl, float alpha)
|
||||||
|
{
|
||||||
|
this.hsl = hsl;
|
||||||
|
this.alpha = alpha;
|
||||||
|
rgb = toRGB(hsl, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object based on this HSLColor with a different
|
||||||
|
* Hue value. The degrees specified is an absolute value.
|
||||||
|
*
|
||||||
|
* @param degrees - the Hue value between 0 - 360
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color adjustHue(float degrees)
|
||||||
|
{
|
||||||
|
return toRGB(degrees, hsl[1], hsl[2], alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object based on this HSLColor with a different
|
||||||
|
* Luminance value. The percent specified is an absolute value.
|
||||||
|
*
|
||||||
|
* @param percent - the Luminance value between 0 - 100
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color adjustLuminance(float percent)
|
||||||
|
{
|
||||||
|
return toRGB(hsl[0], hsl[1], percent, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object based on this HSLColor with a different
|
||||||
|
* Saturation value. The percent specified is an absolute value.
|
||||||
|
*
|
||||||
|
* @param percent - the Saturation value between 0 - 100
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color adjustSaturation(float percent)
|
||||||
|
{
|
||||||
|
return toRGB(hsl[0], percent, hsl[2], alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object based on this HSLColor with a different
|
||||||
|
* Shade. Changing the shade will return a darker color. The percent
|
||||||
|
* specified is a relative value.
|
||||||
|
*
|
||||||
|
* @param percent - the value between 0 - 100
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color adjustShade(float percent)
|
||||||
|
{
|
||||||
|
float multiplier = (100.0f - percent) / 100.0f;
|
||||||
|
float l = Math.max(0.0f, hsl[2] * multiplier);
|
||||||
|
|
||||||
|
return toRGB(hsl[0], hsl[1], l, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object based on this HSLColor with a different
|
||||||
|
* Tone. Changing the tone will return a lighter color. The percent
|
||||||
|
* specified is a relative value.
|
||||||
|
*
|
||||||
|
* @param percent - the value between 0 - 100
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color adjustTone(float percent)
|
||||||
|
{
|
||||||
|
float multiplier = (100.0f + percent) / 100.0f;
|
||||||
|
float l = Math.min(100.0f, hsl[2] * multiplier);
|
||||||
|
|
||||||
|
return toRGB(hsl[0], hsl[1], l, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Alpha value.
|
||||||
|
*
|
||||||
|
* @return the Alpha value.
|
||||||
|
*/
|
||||||
|
public float getAlpha()
|
||||||
|
{
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RGB Color object that is the complementary color of this
|
||||||
|
* HSLColor. This is a convenience method. The complementary color is
|
||||||
|
* determined by adding 180 degrees to the Hue value.
|
||||||
|
* @return the RGB Color object
|
||||||
|
*/
|
||||||
|
public Color getComplementary()
|
||||||
|
{
|
||||||
|
float hue = (hsl[0] + 180.0f) % 360.0f;
|
||||||
|
return toRGB(hue, hsl[1], hsl[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Hue value.
|
||||||
|
*
|
||||||
|
* @return the Hue value.
|
||||||
|
*/
|
||||||
|
public float getHue()
|
||||||
|
{
|
||||||
|
return hsl[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HSL values.
|
||||||
|
*
|
||||||
|
* @return the HSL values.
|
||||||
|
*/
|
||||||
|
public float[] getHSL()
|
||||||
|
{
|
||||||
|
return hsl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Luminance value.
|
||||||
|
*
|
||||||
|
* @return the Luminance value.
|
||||||
|
*/
|
||||||
|
public float getLuminance()
|
||||||
|
{
|
||||||
|
return hsl[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the RGB Color object represented by this HDLColor.
|
||||||
|
*
|
||||||
|
* @return the RGB Color object.
|
||||||
|
*/
|
||||||
|
public Color getRGB()
|
||||||
|
{
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Saturation value.
|
||||||
|
*
|
||||||
|
* @return the Saturation value.
|
||||||
|
*/
|
||||||
|
public float getSaturation()
|
||||||
|
{
|
||||||
|
return hsl[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String toString =
|
||||||
|
"HSLColor[h=" + hsl[0] +
|
||||||
|
",s=" + hsl[1] +
|
||||||
|
",l=" + hsl[2] +
|
||||||
|
",alpha=" + alpha + "]";
|
||||||
|
|
||||||
|
return toString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a RGB Color to it corresponding HSL values.
|
||||||
|
*
|
||||||
|
* @return an array containing the 3 HSL values.
|
||||||
|
*/
|
||||||
|
public static float[] fromRGB(Color color)
|
||||||
|
{
|
||||||
|
// Get RGB values in the range 0 - 1
|
||||||
|
|
||||||
|
float[] rgb = color.getRGBColorComponents( null );
|
||||||
|
float r = rgb[0];
|
||||||
|
float g = rgb[1];
|
||||||
|
float b = rgb[2];
|
||||||
|
|
||||||
|
// Minimum and Maximum RGB values are used in the HSL calculations
|
||||||
|
|
||||||
|
float min = Math.min(r, Math.min(g, b));
|
||||||
|
float max = Math.max(r, Math.max(g, b));
|
||||||
|
|
||||||
|
// Calculate the Hue
|
||||||
|
|
||||||
|
float h = 0;
|
||||||
|
|
||||||
|
if (max == min)
|
||||||
|
h = 0;
|
||||||
|
else if (max == r)
|
||||||
|
h = ((60 * (g - b) / (max - min)) + 360) % 360;
|
||||||
|
else if (max == g)
|
||||||
|
h = (60 * (b - r) / (max - min)) + 120;
|
||||||
|
else if (max == b)
|
||||||
|
h = (60 * (r - g) / (max - min)) + 240;
|
||||||
|
|
||||||
|
// Calculate the Luminance
|
||||||
|
|
||||||
|
float l = (max + min) / 2;
|
||||||
|
// System.out.println(max + " : " + min + " : " + l);
|
||||||
|
|
||||||
|
// Calculate the Saturation
|
||||||
|
|
||||||
|
float s = 0;
|
||||||
|
|
||||||
|
if (max == min)
|
||||||
|
s = 0;
|
||||||
|
else if (l <= .5f)
|
||||||
|
s = (max - min) / (max + min);
|
||||||
|
else
|
||||||
|
s = (max - min) / (2 - max - min);
|
||||||
|
|
||||||
|
// System.out.println(new HSLColor( new float[] {h, s * 100, l * 100} ));
|
||||||
|
return new float[] {h, s * 100, l * 100};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HSL values to a RGB Color with a default alpha value of 1.
|
||||||
|
* H (Hue) is specified as degrees in the range 0 - 360.
|
||||||
|
* S (Saturation) is specified as a percentage in the range 1 - 100.
|
||||||
|
* L (Lumanance) is specified as a percentage in the range 1 - 100.
|
||||||
|
*
|
||||||
|
* @param hsl an array containing the 3 HSL values
|
||||||
|
*
|
||||||
|
* @returns the RGB Color object
|
||||||
|
*/
|
||||||
|
public static Color toRGB(float[] hsl)
|
||||||
|
{
|
||||||
|
return toRGB(hsl, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HSL values to a RGB Color.
|
||||||
|
* H (Hue) is specified as degrees in the range 0 - 360.
|
||||||
|
* S (Saturation) is specified as a percentage in the range 1 - 100.
|
||||||
|
* L (Lumanance) is specified as a percentage in the range 1 - 100.
|
||||||
|
*
|
||||||
|
* @param hsl an array containing the 3 HSL values
|
||||||
|
* @param alpha the alpha value between 0 - 1
|
||||||
|
*
|
||||||
|
* @returns the RGB Color object
|
||||||
|
*/
|
||||||
|
public static Color toRGB(float[] hsl, float alpha)
|
||||||
|
{
|
||||||
|
return toRGB(hsl[0], hsl[1], hsl[2], alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HSL values to a RGB Color with a default alpha value of 1.
|
||||||
|
*
|
||||||
|
* @param h Hue is specified as degrees in the range 0 - 360.
|
||||||
|
* @param s Saturation is specified as a percentage in the range 1 - 100.
|
||||||
|
* @param l Lumanance is specified as a percentage in the range 1 - 100.
|
||||||
|
*
|
||||||
|
* @returns the RGB Color object
|
||||||
|
*/
|
||||||
|
public static Color toRGB(float h, float s, float l)
|
||||||
|
{
|
||||||
|
return toRGB(h, s, l, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HSL values to a RGB Color.
|
||||||
|
*
|
||||||
|
* @param h Hue is specified as degrees in the range 0 - 360.
|
||||||
|
* @param s Saturation is specified as a percentage in the range 1 - 100.
|
||||||
|
* @param l Lumanance is specified as a percentage in the range 1 - 100.
|
||||||
|
* @param alpha the alpha value between 0 - 1
|
||||||
|
*
|
||||||
|
* @returns the RGB Color object
|
||||||
|
*/
|
||||||
|
public static Color toRGB(float h, float s, float l, float alpha)
|
||||||
|
{
|
||||||
|
if (s <0.0f || s > 100.0f)
|
||||||
|
{
|
||||||
|
String message = "Color parameter outside of expected range - Saturation";
|
||||||
|
throw new IllegalArgumentException( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l <0.0f || l > 100.0f)
|
||||||
|
{
|
||||||
|
String message = "Color parameter outside of expected range - Luminance";
|
||||||
|
throw new IllegalArgumentException( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alpha <0.0f || alpha > 1.0f)
|
||||||
|
{
|
||||||
|
String message = "Color parameter outside of expected range - Alpha";
|
||||||
|
throw new IllegalArgumentException( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formula needs all values between 0 - 1.
|
||||||
|
|
||||||
|
h = h % 360.0f;
|
||||||
|
h /= 360f;
|
||||||
|
s /= 100f;
|
||||||
|
l /= 100f;
|
||||||
|
|
||||||
|
float q = 0;
|
||||||
|
|
||||||
|
if (l < 0.5)
|
||||||
|
q = l * (1 + s);
|
||||||
|
else
|
||||||
|
q = (l + s) - (s * l);
|
||||||
|
|
||||||
|
float p = 2 * l - q;
|
||||||
|
|
||||||
|
float r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)));
|
||||||
|
float g = Math.max(0, HueToRGB(p, q, h));
|
||||||
|
float b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)));
|
||||||
|
|
||||||
|
r = Math.min(r, 1.0f);
|
||||||
|
g = Math.min(g, 1.0f);
|
||||||
|
b = Math.min(b, 1.0f);
|
||||||
|
|
||||||
|
return new Color(r, g, b, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float HueToRGB(float p, float q, float h)
|
||||||
|
{
|
||||||
|
if (h < 0) h += 1;
|
||||||
|
|
||||||
|
if (h > 1 ) h -= 1;
|
||||||
|
|
||||||
|
if (6 * h < 1)
|
||||||
|
{
|
||||||
|
return p + ((q - p) * 6 * h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (2 * h < 1 )
|
||||||
|
{
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (3 * h < 2)
|
||||||
|
{
|
||||||
|
return p + ( (q - p) * 6 * ((2.0f / 3.0f) - h) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
@cellFocusColor=000000
|
@cellFocusColor=000000
|
||||||
@icon=adadad
|
@icon=adadad
|
||||||
|
|
||||||
|
# Button
|
||||||
|
@buttonHoverBackground=lighten(3%,autoInverse)
|
||||||
|
@buttonPressedBackground=lighten(6%,autoInverse)
|
||||||
|
|
||||||
|
|
||||||
#---- globals ----
|
#---- globals ----
|
||||||
|
|
||||||
@@ -63,8 +67,8 @@ window=@background
|
|||||||
#---- Button ----
|
#---- Button ----
|
||||||
|
|
||||||
Button.background=4c5052
|
Button.background=4c5052
|
||||||
Button.hoverBackground=525658
|
Button.hoverBackground=@buttonHoverBackground
|
||||||
Button.pressedBackground=5c6164
|
Button.pressedBackground=@buttonPressedBackground
|
||||||
|
|
||||||
Button.borderColor=5e6060
|
Button.borderColor=5e6060
|
||||||
Button.disabledBorderColor=5e6060
|
Button.disabledBorderColor=5e6060
|
||||||
@@ -73,8 +77,8 @@ Button.hoverBorderColor=@@Button.focusedBorderColor
|
|||||||
|
|
||||||
Button.default.background=365880
|
Button.default.background=365880
|
||||||
Button.default.foreground=bbbbbb
|
Button.default.foreground=bbbbbb
|
||||||
Button.default.hoverBackground=3d6185
|
Button.default.hoverBackground=@buttonHoverBackground
|
||||||
Button.default.pressedBackground=43688c
|
Button.default.pressedBackground=@buttonPressedBackground
|
||||||
Button.default.borderColor=4c708c
|
Button.default.borderColor=4c708c
|
||||||
Button.default.hoverBorderColor=537699
|
Button.default.hoverBorderColor=537699
|
||||||
Button.default.focusedBorderColor=537699
|
Button.default.focusedBorderColor=537699
|
||||||
@@ -95,8 +99,8 @@ CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor
|
|||||||
CheckBox.icon.selectedFocusedBorderColor=466D94
|
CheckBox.icon.selectedFocusedBorderColor=466D94
|
||||||
CheckBox.icon.background=43494A
|
CheckBox.icon.background=43494A
|
||||||
CheckBox.icon.disabledBackground=@background
|
CheckBox.icon.disabledBackground=@background
|
||||||
CheckBox.icon.hoverBackground=4c5052
|
CheckBox.icon.hoverBackground=@buttonHoverBackground
|
||||||
CheckBox.icon.pressedBackground=@@Button.pressedBackground
|
CheckBox.icon.pressedBackground=@buttonPressedBackground
|
||||||
CheckBox.icon.selectedBackground=43494A
|
CheckBox.icon.selectedBackground=43494A
|
||||||
CheckBox.icon.checkmarkColor=A7A7A7
|
CheckBox.icon.checkmarkColor=A7A7A7
|
||||||
CheckBox.icon.disabledCheckmarkColor=606060
|
CheckBox.icon.disabledCheckmarkColor=606060
|
||||||
|
|||||||
@@ -31,6 +31,10 @@
|
|||||||
@cellFocusColor=000000
|
@cellFocusColor=000000
|
||||||
@icon=afafaf
|
@icon=afafaf
|
||||||
|
|
||||||
|
# Button
|
||||||
|
@buttonHoverBackground=darken(3%,autoInverse)
|
||||||
|
@buttonPressedBackground=darken(10%,autoInverse)
|
||||||
|
|
||||||
|
|
||||||
#---- globals ----
|
#---- globals ----
|
||||||
|
|
||||||
@@ -64,8 +68,8 @@ window=@background
|
|||||||
|
|
||||||
Button.background=ffffff
|
Button.background=ffffff
|
||||||
Button.focusedBackground=e3f1fa
|
Button.focusedBackground=e3f1fa
|
||||||
Button.hoverBackground=f8f8f8
|
Button.hoverBackground=@buttonHoverBackground
|
||||||
Button.pressedBackground=dfdfdf
|
Button.pressedBackground=@buttonPressedBackground
|
||||||
|
|
||||||
Button.borderColor=bfbfbf
|
Button.borderColor=bfbfbf
|
||||||
Button.disabledBorderColor=cfcfcf
|
Button.disabledBorderColor=cfcfcf
|
||||||
@@ -75,8 +79,8 @@ Button.hoverBorderColor=@@Button.focusedBorderColor
|
|||||||
Button.default.background=@@Button.background
|
Button.default.background=@@Button.background
|
||||||
Button.default.foreground=@foreground
|
Button.default.foreground=@foreground
|
||||||
Button.default.focusedBackground=@@Button.focusedBackground
|
Button.default.focusedBackground=@@Button.focusedBackground
|
||||||
Button.default.hoverBackground=@@Button.hoverBackground
|
Button.default.hoverBackground=@buttonHoverBackground
|
||||||
Button.default.pressedBackground=@@Button.pressedBackground
|
Button.default.pressedBackground=@buttonPressedBackground
|
||||||
Button.default.borderColor=4D89C9
|
Button.default.borderColor=4D89C9
|
||||||
Button.default.hoverBorderColor=@@Button.hoverBorderColor
|
Button.default.hoverBorderColor=@@Button.hoverBorderColor
|
||||||
Button.default.focusedBorderColor=@@Button.focusedBorderColor
|
Button.default.focusedBorderColor=@@Button.focusedBorderColor
|
||||||
@@ -97,8 +101,8 @@ CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor
|
|||||||
CheckBox.icon.background=FFFFFF
|
CheckBox.icon.background=FFFFFF
|
||||||
CheckBox.icon.disabledBackground=@background
|
CheckBox.icon.disabledBackground=@background
|
||||||
CheckBox.icon.focusedBackground=@@Button.focusedBackground
|
CheckBox.icon.focusedBackground=@@Button.focusedBackground
|
||||||
CheckBox.icon.hoverBackground=@@Button.hoverBackground
|
CheckBox.icon.hoverBackground=@buttonHoverBackground
|
||||||
CheckBox.icon.pressedBackground=@@Button.pressedBackground
|
CheckBox.icon.pressedBackground=@buttonPressedBackground
|
||||||
CheckBox.icon.selectedBackground=FFFFFF
|
CheckBox.icon.selectedBackground=FFFFFF
|
||||||
CheckBox.icon.checkmarkColor=4D89C9
|
CheckBox.icon.checkmarkColor=4D89C9
|
||||||
CheckBox.icon.disabledCheckmarkColor=ABABAB
|
CheckBox.icon.disabledCheckmarkColor=ABABAB
|
||||||
|
|||||||
Reference in New Issue
Block a user