mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-10 22:17:13 -06:00
Theme Editor: support color preview for color functions
UIDefaultsLoader: made some private methods package private and return parsed valued type
This commit is contained in:
@@ -167,7 +167,8 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
String value = resolveValue( properties, (String) e.getValue() );
|
String value = resolveValue( properties, (String) e.getValue() );
|
||||||
try {
|
try {
|
||||||
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver, addonClassLoaders ) );
|
globals.put( key.substring( GLOBAL_PREFIX.length() ),
|
||||||
|
parseValue( key, value, null, resolver, addonClassLoaders ) );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
logParseError( Level.SEVERE, key, value, ex );
|
logParseError( Level.SEVERE, key, value, ex );
|
||||||
}
|
}
|
||||||
@@ -192,7 +193,7 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
String value = resolveValue( properties, (String) e.getValue() );
|
String value = resolveValue( properties, (String) e.getValue() );
|
||||||
try {
|
try {
|
||||||
defaults.put( key, parseValue( key, value, resolver, addonClassLoaders ) );
|
defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
logParseError( Level.SEVERE, key, value, ex );
|
logParseError( Level.SEVERE, key, value, ex );
|
||||||
}
|
}
|
||||||
@@ -206,7 +207,7 @@ class UIDefaultsLoader
|
|||||||
FlatLaf.LOG.log( level, "FlatLaf: Failed to parse: '" + key + '=' + value + '\'', ex );
|
FlatLaf.LOG.log( level, "FlatLaf: Failed to parse: '" + key + '=' + value + '\'', ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveValue( Properties properties, String value ) {
|
static String resolveValue( Properties properties, String value ) {
|
||||||
if( value.startsWith( PROPERTY_PREFIX ) )
|
if( value.startsWith( PROPERTY_PREFIX ) )
|
||||||
value = value.substring( PROPERTY_PREFIX.length() );
|
value = value.substring( PROPERTY_PREFIX.length() );
|
||||||
else if( !value.startsWith( VARIABLE_PREFIX ) )
|
else if( !value.startsWith( VARIABLE_PREFIX ) )
|
||||||
@@ -229,26 +230,34 @@ class UIDefaultsLoader
|
|||||||
return resolveValue( properties, newValue );
|
return resolveValue( properties, newValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ValueType { UNKNOWN, STRING, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
|
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
|
||||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER }
|
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
||||||
|
|
||||||
|
private static ValueType[] tempResultValueType = new ValueType[1];
|
||||||
|
|
||||||
static Object parseValue( String key, String value ) {
|
static Object parseValue( String key, String value ) {
|
||||||
return parseValue( key, value, v -> v, Collections.emptyList() );
|
return parseValue( key, value, null, v -> v, Collections.emptyList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseValue( String key, String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
static Object parseValue( String key, String value, ValueType[] resultValueType,
|
||||||
|
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
|
{
|
||||||
|
if( resultValueType == null )
|
||||||
|
resultValueType = tempResultValueType;
|
||||||
|
|
||||||
value = value.trim();
|
value = value.trim();
|
||||||
|
|
||||||
// null, false, true
|
// null, false, true
|
||||||
switch( value ) {
|
switch( value ) {
|
||||||
case "null": return null;
|
case "null": resultValueType[0] = ValueType.NULL; return null;
|
||||||
case "false": return false;
|
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
|
||||||
case "true": return true;
|
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for function "lazy"
|
// check for function "lazy"
|
||||||
// Syntax: lazy(uiKey)
|
// Syntax: lazy(uiKey)
|
||||||
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
||||||
|
resultValueType[0] = ValueType.LAZY;
|
||||||
String uiKey = value.substring( 5, value.length() - 1 ).trim();
|
String uiKey = value.substring( 5, value.length() - 1 ).trim();
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
return lazyUIManagerGet( uiKey );
|
return lazyUIManagerGet( uiKey );
|
||||||
@@ -301,6 +310,8 @@ class UIDefaultsLoader
|
|||||||
valueType = ValueType.GRAYFILTER;
|
valueType = ValueType.GRAYFILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultValueType[0] = valueType;
|
||||||
|
|
||||||
// parse value
|
// parse value
|
||||||
switch( valueType ) {
|
switch( valueType ) {
|
||||||
case STRING: return value;
|
case STRING: return value;
|
||||||
@@ -323,20 +334,27 @@ class UIDefaultsLoader
|
|||||||
default:
|
default:
|
||||||
// colors
|
// colors
|
||||||
Object color = parseColorOrFunction( value, resolver, false );
|
Object color = parseColorOrFunction( value, resolver, false );
|
||||||
if( color != null )
|
if( color != null ) {
|
||||||
|
resultValueType[0] = ValueType.COLOR;
|
||||||
return color;
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
// integer
|
// integer
|
||||||
Integer integer = parseInteger( value, false );
|
Integer integer = parseInteger( value, false );
|
||||||
if( integer != null )
|
if( integer != null ) {
|
||||||
|
resultValueType[0] = ValueType.INTEGER;
|
||||||
return integer;
|
return integer;
|
||||||
|
}
|
||||||
|
|
||||||
// float
|
// float
|
||||||
Float f = parseFloat( value, false );
|
Float f = parseFloat( value, false );
|
||||||
if( f != null )
|
if( f != null ) {
|
||||||
|
resultValueType[0] = ValueType.FLOAT;
|
||||||
return f;
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
|
resultValueType[0] = ValueType.STRING;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation( project( ":flatlaf-core" ) )
|
implementation( project( ":flatlaf-core" ) )
|
||||||
|
|
||||||
implementation( "com.fifesoft:rsyntaxtextarea:3.1.0" )
|
implementation( "com.fifesoft:rsyntaxtextarea:3.1.1" )
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import com.formdev.flatlaf.UIDefaultsLoader.ValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable accessing package private methods of {@link UIDefaultsLoader}.
|
* Enable accessing package private methods of {@link UIDefaultsLoader}.
|
||||||
*
|
*
|
||||||
@@ -23,6 +28,40 @@ package com.formdev.flatlaf;
|
|||||||
*/
|
*/
|
||||||
public class UIDefaultsLoaderAccessor
|
public class UIDefaultsLoaderAccessor
|
||||||
{
|
{
|
||||||
|
public static Object UNKNOWN = ValueType.UNKNOWN;
|
||||||
|
public static Object STRING = ValueType.STRING;
|
||||||
|
public static Object BOOLEAN = ValueType.BOOLEAN;
|
||||||
|
public static Object CHARACTER = ValueType.CHARACTER;
|
||||||
|
public static Object INTEGER = ValueType.INTEGER;
|
||||||
|
public static Object FLOAT = ValueType.FLOAT;
|
||||||
|
public static Object BORDER = ValueType.BORDER;
|
||||||
|
public static Object ICON = ValueType.ICON;
|
||||||
|
public static Object INSETS = ValueType.INSETS;
|
||||||
|
public static Object DIMENSION = ValueType.DIMENSION;
|
||||||
|
public static Object COLOR = ValueType.COLOR;
|
||||||
|
public static Object SCALEDINTEGER = ValueType.SCALEDINTEGER;
|
||||||
|
public static Object SCALEDFLOAT = ValueType.SCALEDFLOAT;
|
||||||
|
public static Object SCALEDINSETS = ValueType.SCALEDINSETS;
|
||||||
|
public static Object SCALEDDIMENSION = ValueType.SCALEDDIMENSION;
|
||||||
|
public static Object INSTANCE = ValueType.INSTANCE;
|
||||||
|
public static Object CLASS = ValueType.CLASS;
|
||||||
|
public static Object GRAYFILTER = ValueType.GRAYFILTER;
|
||||||
|
public static Object NULL = ValueType.NULL;
|
||||||
|
public static Object LAZY = ValueType.LAZY;
|
||||||
|
|
||||||
|
public static String resolveValue( Properties properties, String value ) {
|
||||||
|
return UIDefaultsLoader.resolveValue( properties, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object parseValue( String key, String value, Object[] resultValueType,
|
||||||
|
Function<String, String> resolver )
|
||||||
|
{
|
||||||
|
ValueType[] resultValueType2 = new ValueType[1];
|
||||||
|
Object result = UIDefaultsLoader.parseValue( key, value, resultValueType2, resolver, Collections.emptyList() );
|
||||||
|
resultValueType[0] = resultValueType2[0];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static int parseColorRGBA( String value ) {
|
public static int parseColorRGBA( String value ) {
|
||||||
return UIDefaultsLoader.parseColorRGBA( value );
|
return UIDefaultsLoader.parseColorRGBA( value );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class FlatSyntaxTextArea
|
|||||||
{
|
{
|
||||||
private boolean useColorOfColorTokens;
|
private boolean useColorOfColorTokens;
|
||||||
|
|
||||||
|
final FlatThemePropertiesSupport propertiesSupport = new FlatThemePropertiesSupport( this );
|
||||||
private final Map<String, Color> parsedColorsMap = new HashMap<>();
|
private final Map<String, Color> parsedColorsMap = new HashMap<>();
|
||||||
|
|
||||||
FlatSyntaxTextArea() {
|
FlatSyntaxTextArea() {
|
||||||
|
|||||||
@@ -103,11 +103,18 @@ class FlatThemeEditorOverlay
|
|||||||
g.setColor( color );
|
g.setColor( color );
|
||||||
g.fillRect( px, r.y, pw, r.height );
|
g.fillRect( px, r.y, pw, r.height );
|
||||||
|
|
||||||
|
// if color is semi-transparent paint also none-transparent color
|
||||||
|
int alpha = color.getAlpha();
|
||||||
|
if( alpha != 255 && pw > r.height * 2 ) {
|
||||||
|
g.setColor( new Color( color.getRGB() ) );
|
||||||
|
g.fillRect( px + pw - r.height, r.y, r.height, r.height );
|
||||||
|
}
|
||||||
|
|
||||||
// paint text
|
// paint text
|
||||||
int textX = px - maxTextWidth;
|
int textX = px - maxTextWidth;
|
||||||
if( textX > r.x + gap) {
|
if( textX > r.x + gap) {
|
||||||
float[] hsl = HSLColor.fromRGB( color );
|
float[] hsl = HSLColor.fromRGB( color );
|
||||||
String hslStr = String.format( "HSL %d %d %d",
|
String hslStr = String.format( "HSL %3d %2d %2d",
|
||||||
Math.round( hsl[0] ), Math.round( hsl[1] ), Math.round( hsl[2] ) );
|
Math.round( hsl[0] ), Math.round( hsl[1] ), Math.round( hsl[2] ) );
|
||||||
g.setColor( textArea.getForeground() );
|
g.setColor( textArea.getForeground() );
|
||||||
FlatUIUtils.drawString( textArea, g, hslStr, textX,
|
FlatUIUtils.drawString( textArea, g, hslStr, textX,
|
||||||
@@ -120,6 +127,10 @@ class FlatThemeEditorOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Color getColorInLine( FlatSyntaxTextArea textArea, int line ) {
|
private Color getColorInLine( FlatSyntaxTextArea textArea, int line ) {
|
||||||
|
Object value = textArea.propertiesSupport.getParsedValueAtLine( line );
|
||||||
|
if( value instanceof Color )
|
||||||
|
return (Color) value;
|
||||||
|
|
||||||
Token token = textArea.getTokenListForLine( line );
|
Token token = textArea.getTokenListForLine( line );
|
||||||
for( Token t = token; t != null && t.isPaintable(); t = t.getNextToken() ) {
|
for( Token t = token; t != null && t.isPaintable(); t = t.getNextToken() ) {
|
||||||
if( t.getType() == FlatThemeTokenMaker.TOKEN_COLOR ) {
|
if( t.getType() == FlatThemeTokenMaker.TOKEN_COLOR ) {
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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
|
||||||
|
*
|
||||||
|
* https://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.themeeditor;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports parsing content of text area in FlatLaf properties syntax.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatThemePropertiesSupport
|
||||||
|
implements DocumentListener
|
||||||
|
{
|
||||||
|
private final FlatSyntaxTextArea textArea;
|
||||||
|
private final Function<String, String> resolver;
|
||||||
|
private Properties propertiesCache;
|
||||||
|
private final Map<Integer, Object> parsedValueCache = new HashMap<>();
|
||||||
|
|
||||||
|
FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) {
|
||||||
|
this.textArea = textArea;
|
||||||
|
|
||||||
|
resolver = v -> {
|
||||||
|
return resolveValue( v );
|
||||||
|
};
|
||||||
|
|
||||||
|
textArea.getDocument().addDocumentListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveValue( String value ) {
|
||||||
|
return UIDefaultsLoaderAccessor.resolveValue( getProperties(), value );
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getParsedValueAtLine( int line ) {
|
||||||
|
Integer lineKey = line;
|
||||||
|
Object parsedValue = parsedValueCache.get( lineKey );
|
||||||
|
if( parsedValue != null )
|
||||||
|
return !(parsedValue instanceof Exception) ? parsedValue : null;
|
||||||
|
|
||||||
|
KeyValue keyValue = getKeyValueAtLine( line );
|
||||||
|
if( keyValue == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object[] resultValueType = new Object[1];
|
||||||
|
String value = resolveValue( keyValue.value );
|
||||||
|
parsedValue = UIDefaultsLoaderAccessor.parseValue( keyValue.key, value, resultValueType, resolver );
|
||||||
|
parsedValueCache.put( lineKey, parsedValue );
|
||||||
|
return parsedValue;
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
System.out.println( ex.getMessage() ); //TODO
|
||||||
|
parsedValueCache.put( lineKey, ex );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyValue getKeyValueAtLine( int line ) {
|
||||||
|
try {
|
||||||
|
int startOffset = textArea.getLineStartOffset( line );
|
||||||
|
int endOffset = textArea.getLineEndOffset( line );
|
||||||
|
String text = textArea.getText( startOffset, endOffset - startOffset );
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load( new StringReader( text ) );
|
||||||
|
if( properties.isEmpty() )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String key = (String) properties.keys().nextElement();
|
||||||
|
String value = properties.getProperty( key );
|
||||||
|
return new KeyValue( key, value );
|
||||||
|
} catch( BadLocationException | IOException ex ) {
|
||||||
|
// ignore
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties getProperties() {
|
||||||
|
if( propertiesCache != null )
|
||||||
|
return propertiesCache;
|
||||||
|
|
||||||
|
propertiesCache = new Properties();
|
||||||
|
try {
|
||||||
|
propertiesCache.load( new StringReader( textArea.getText() ) );
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
ex.printStackTrace(); //TODO
|
||||||
|
}
|
||||||
|
return propertiesCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearCache() {
|
||||||
|
propertiesCache = null;
|
||||||
|
parsedValueCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface DocumentListener ----
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate( DocumentEvent e ) {
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate( DocumentEvent e ) {
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate( DocumentEvent e ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class KeyValue -----------------------------------------------------
|
||||||
|
|
||||||
|
static class CacheLineInfo {
|
||||||
|
Object parsedValue;
|
||||||
|
Object valueType;
|
||||||
|
Exception parseError;
|
||||||
|
|
||||||
|
Color origColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class KeyValue -----------------------------------------------------
|
||||||
|
|
||||||
|
static class KeyValue {
|
||||||
|
final String key;
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
KeyValue( String key, String value ) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,8 +33,8 @@ Prop.lazy=lazy(Prop.string)
|
|||||||
|
|
||||||
Prop.colorFunc1=rgb(12,34,56)
|
Prop.colorFunc1=rgb(12,34,56)
|
||||||
Prop.colorFunc2=rgba(12,34,56,78)
|
Prop.colorFunc2=rgba(12,34,56,78)
|
||||||
Prop.colorFunc3=hsl(12,34,56)
|
Prop.colorFunc3=hsl(12,34%,56%)
|
||||||
Prop.colorFunc4=hsla(12,34,56,78)
|
Prop.colorFunc4=hsla(12,34%,56%,78%)
|
||||||
|
|
||||||
Prop.colorFunc5=lighten(#fe1289,20%)
|
Prop.colorFunc5=lighten(#fe1289,20%)
|
||||||
Prop.colorFunc6=darken(#fe1289,20%)
|
Prop.colorFunc6=darken(#fe1289,20%)
|
||||||
|
|||||||
Reference in New Issue
Block a user