UI defaults inspector:

- show computed derived colors
- also show base colors and default colors
- indicate derived colors with magenta bar on right side in value column
This commit is contained in:
Karl Tauber
2021-01-15 19:07:44 +01:00
parent ed5180ffd6
commit c43249316c
4 changed files with 321 additions and 11 deletions

View File

@@ -21,11 +21,14 @@ import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
@@ -45,6 +48,7 @@ import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.ui.FlatMarginBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.HSLColor;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
@@ -72,6 +76,7 @@ public class FlatUIDefaultsInspector
private final PropertyChangeListener lafListener = this::lafChanged;
private final PropertyChangeListener lafDefaultsListener = this::lafDefaultsChanged;
private boolean refreshPending;
private Properties derivedColorKeys;
/**
* Installs a key listener into the application that allows enabling and disabling
@@ -298,6 +303,7 @@ public class FlatUIDefaultsInspector
Set<Entry<Object, Object>> defaultsSet = defaults.entrySet();
ArrayList<Item> items = new ArrayList<>( defaultsSet.size() );
HashSet<Object> keys = new HashSet<>( defaultsSet.size() );
Color[] pBaseColor = new Color[1];
for( Entry<Object,Object> e : defaultsSet ) {
Object key = e.getKey();
@@ -314,6 +320,13 @@ public class FlatUIDefaultsInspector
if( !keys.add( key ) )
continue;
// resolve derived color
if( value instanceof DerivedColor ) {
Color resolvedColor = resolveDerivedColor( defaults, (String) key, (DerivedColor) value, pBaseColor );
if( resolvedColor != value )
value = new Color[] { resolvedColor, pBaseColor[0], (Color) value };
}
// check whether key was overridden using UIManager.put(key,value)
Object lafValue = null;
if( defaults.containsKey( key ) )
@@ -326,6 +339,51 @@ public class FlatUIDefaultsInspector
return items.toArray( new Item[items.size()] );
}
private Color resolveDerivedColor( UIDefaults defaults, String key, Color color, Color[] pBaseColor ) {
if( pBaseColor != null )
pBaseColor[0] = null;
if( !(color instanceof DerivedColor) )
return color;
if( derivedColorKeys == null )
derivedColorKeys = loadDerivedColorKeys();
Object baseKey = derivedColorKeys.get( key );
if( baseKey == null )
return color;
// this is for keys that may be defined as derived colors, but do not derive them at runtime
if( "null".equals( baseKey ) )
return color;
Color baseColor = defaults.getColor( baseKey );
if( baseColor == null )
return color;
if( baseColor instanceof DerivedColor )
baseColor = resolveDerivedColor( defaults, (String) baseKey, baseColor, null );
if( pBaseColor != null )
pBaseColor[0] = baseColor;
Color newColor = FlatUIUtils.deriveColor( color, baseColor );
// creating a new color instance to drop Color.frgbvalue from newColor
// and avoid rounding issues/differences
return new Color( newColor.getRGB(), true );
}
private Properties loadDerivedColorKeys() {
Properties properties = new Properties();
try( InputStream in = getClass().getResourceAsStream( "/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties" ) ) {
properties.load( in );
} catch( IOException ex ) {
ex.printStackTrace();
}
return properties;
}
private static void updateWindowTitle( JFrame frame ) {
String title = frame.getTitle();
String sep = " - ";
@@ -382,7 +440,7 @@ public class FlatUIDefaultsInspector
return "Boolean";
if( value instanceof Border )
return "Border";
if( value instanceof Color )
if( value instanceof Color || value instanceof Color[] )
return "Color";
if( value instanceof Dimension )
return "Dimension";
@@ -590,8 +648,8 @@ public class FlatUIDefaultsInspector
}
static String valueAsString( Object value ) {
if( value instanceof Color ) {
Color color = (Color) value;
if( value instanceof Color || value instanceof Color[] ) {
Color color = (value instanceof Color[]) ? ((Color[])value)[0] : (Color) value;
HSLColor hslColor = new HSLColor( color );
if( color.getAlpha() == 255 ) {
return String.format( "%s rgb(%d, %d, %d) hsl(%d, %d, %d)",
@@ -628,7 +686,7 @@ public class FlatUIDefaultsInspector
if( border instanceof FlatLineBorder ) {
FlatLineBorder lineBorder = (FlatLineBorder) border;
return valueAsString( lineBorder.getUnscaledBorderInsets() )
+ " " + Item.color2hex( lineBorder.getLineColor() )
+ " " + color2hex( lineBorder.getLineColor() )
+ " " + lineBorder.getLineThickness()
+ " " + border.getClass().getName();
} else if( border instanceof EmptyBorder ) {
@@ -898,7 +956,7 @@ public class FlatUIDefaultsInspector
init( table, item.key, isSelected, row );
// reset background, foreground and icon
if( !(item.value instanceof Color) ) {
if( !(item.value instanceof Color) && !(item.value instanceof Color[]) ) {
setBackground( null );
setForeground( null );
}
@@ -910,8 +968,8 @@ public class FlatUIDefaultsInspector
super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
if( item.value instanceof Color ) {
Color color = (Color) item.value;
if( item.value instanceof Color || item.value instanceof Color[] ) {
Color color = (item.value instanceof Color[]) ? ((Color[])item.value)[0] : (Color) item.value;
boolean isDark = new HSLColor( color ).getLuminance() < 70;
setBackground( color );
setForeground( isDark ? Color.white : Color.black );
@@ -933,10 +991,31 @@ public class FlatUIDefaultsInspector
@Override
protected void paintComponent( Graphics g ) {
if( item.value instanceof Color ) {
// fill background
g.setColor( getBackground() );
g.fillRect( 0, 0, getWidth(), getHeight() );
if( item.value instanceof Color || item.value instanceof Color[] ) {
int width = getWidth();
int height = getHeight();
Color background = getBackground();
// paint color
fillRect( g, background, 0, 0, width, height );
if( item.value instanceof Color[] ) {
// paint base color
int width2 = height * 2;
fillRect( g, ((Color[])item.value)[1], width - width2, 0, width2, height );
// paint default color
Color defaultColor = ((Color[])item.value)[2];
if( defaultColor != null && !defaultColor.equals( background ) ) {
int width3 = height / 2;
fillRect( g, defaultColor, width - width3, 0, width3, height );
}
// paint "derived color" indicator
int width4 = height / 4;
g.setColor( Color.magenta );
g.fillRect( width - width4, 0, width4, height );
}
// layout text
FontMetrics fm = getFontMetrics( getFont() );
@@ -967,6 +1046,17 @@ public class FlatUIDefaultsInspector
paintSeparator( g );
}
private void fillRect( Graphics g, Color color, int x, int y, int width, int height ) {
// fill white if color is translucent
if( color.getAlpha() != 255 ) {
g.setColor( Color.white );
g.fillRect( x, y, width, height );
}
g.setColor( color );
g.fillRect( x, y, width, height );
}
}
//---- class SafeIcon -----------------------------------------------------

View File

@@ -25,4 +25,6 @@ module com.formdev.flatlaf.extras {
exports com.formdev.flatlaf.extras;
exports com.formdev.flatlaf.extras.components;
opens com.formdev.flatlaf.extras.resources;
}

View File

@@ -0,0 +1,212 @@
#
# Copyright 2021 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.
#
#
# This file lists UI keys of colors, which are computed at runtime.
#
# Colors marked as `derived` in properties files are computed at runtime based on
# a variable base color (usually the current background color of a component).
# This works only for a limited set of UI keys.
#
# The property key is the UI key of a color, which is computed at runtime.
# The property value is the UI key of the base color.
#
# This file is not used at runtime.
# It is only used in tooling (e.g. UI Defaults Inspector or UIDefaultsDump).
#
#---- system colors ----
scrollbar = null
#---- Button ----
Button.focusedBackground = Button.background
Button.hoverBackground = Button.background
Button.pressedBackground = Button.background
Button.selectedBackground = Button.background
Button.disabledBackground = Button.background
Button.disabledSelectedBackground = Button.background
Button.default.focusedBackground = Button.default.background
Button.default.hoverBackground = Button.default.background
Button.default.pressedBackground = Button.default.background
Button.toolbar.hoverBackground = Button.background
Button.toolbar.pressedBackground = Button.background
Button.toolbar.selectedBackground = Button.background
#---- CheckBox ----
CheckBox.icon.disabledBackground = CheckBox.icon.background
CheckBox.icon.focusedBackground = CheckBox.icon.background
CheckBox.icon.hoverBackground = CheckBox.icon.background
CheckBox.icon.pressedBackground = CheckBox.icon.background
CheckBox.icon.selectedFocusedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.selectedHoverBackground = CheckBox.icon.selectedBackground
CheckBox.icon.selectedPressedBackground = CheckBox.icon.selectedBackground
CheckBox.icon[filled].disabledBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].focusedBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].hoverBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].pressedBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].selectedFocusedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].selectedHoverBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].selectedPressedBackground = CheckBox.icon[filled].selectedBackground
#---- CheckBoxMenuItem ----
CheckBoxMenuItem.selectionBackground = CheckBoxMenuItem.background
#---- ComboBox ----
ComboBox.buttonDisabledArrowColor = ComboBox.buttonArrowColor
ComboBox.buttonHoverArrowColor = ComboBox.buttonArrowColor
ComboBox.buttonPressedArrowColor = ComboBox.buttonArrowColor
#---- Component ----
Component.custom.borderColor = null
#---- HelpButton ----
HelpButton.disabledBackground = HelpButton.background
HelpButton.focusedBackground = HelpButton.background
HelpButton.hoverBackground = HelpButton.background
HelpButton.pressedBackground = HelpButton.background
#---- InternalFrame ----
InternalFrame.buttonHoverBackground = InternalFrame.activeTitleBackground
InternalFrame.buttonPressedBackground = InternalFrame.activeTitleBackground
#---- Menu ----
Menu.selectionBackground = Menu.background
#---- MenuBar ----
MenuBar.hoverBackground = Menu.background
MenuBar.underlineSelectionBackground = Menu.background
#---- MenuItem ----
MenuItem.checkBackground = MenuItem.selectionBackground
MenuItem.underlineSelectionBackground = MenuItem.background
MenuItem.underlineSelectionCheckBackground = MenuItem.selectionBackground
MenuItem.selectionBackground = MenuItem.background
#---- RadioButtonMenuItem ----
RadioButtonMenuItem.selectionBackground = RadioButtonMenuItem.background
#---- RootPane ----
RootPane.activeBorderColor = Panel.background
RootPane.inactiveBorderColor = Panel.background
#---- ScrollBar ----
ScrollBar.track = ScrollBar.background
ScrollBar.thumb = ScrollBar.track
ScrollBar.hoverTrackColor = ScrollBar.track
ScrollBar.hoverThumbColor = ScrollBar.thumb
ScrollBar.pressedTrackColor = ScrollBar.track
ScrollBar.pressedThumbColor = ScrollBar.thumb
ScrollBar.buttonDisabledArrowColor = ScrollBar.buttonArrowColor
ScrollBar.hoverButtonBackground = ScrollBar.background
ScrollBar.pressedButtonBackground = ScrollBar.background
#---- ScrollPane ----
ScrollPane.background = null
#---- Slider ----
Slider.focusedColor = Component.focusColor
Slider.hoverThumbColor = Slider.thumbColor
Slider.pressedThumbColor = Slider.thumbColor
Slider.disabledThumbColor = Slider.thumbColor
#---- Spinner ----
Spinner.buttonDisabledArrowColor = Spinner.buttonArrowColor
Spinner.buttonHoverArrowColor = Spinner.buttonArrowColor
Spinner.buttonPressedArrowColor = Spinner.buttonArrowColor
#---- SplitPaneDivider ----
SplitPaneDivider.oneTouchHoverArrowColor = SplitPaneDivider.oneTouchArrowColor
SplitPaneDivider.oneTouchPressedArrowColor = SplitPaneDivider.oneTouchArrowColor
#---- TabbedPane ----
TabbedPane.selectedBackground = TabbedPane.background
TabbedPane.hoverColor = TabbedPane.background
TabbedPane.focusColor = TabbedPane.background
TabbedPane.closeBackground = TabbedPane.background
TabbedPane.closeHoverBackground = TabbedPane.background
TabbedPane.closePressedBackground = TabbedPane.background
TabbedPane.closeForeground = TabbedPane.foreground
TabbedPane.closeHoverForeground = TabbedPane.foreground
TabbedPane.closePressedForeground = TabbedPane.foreground
TabbedPane.buttonHoverBackground = TabbedPane.background
TabbedPane.buttonPressedBackground = TabbedPane.background
#---- TitlePane ----
TitlePane.buttonHoverBackground = TitlePane.background
TitlePane.buttonPressedBackground = TitlePane.background
#---- ToggleButton ----
ToggleButton.focusedBackground = ToggleButton.background
ToggleButton.hoverBackground = ToggleButton.background
ToggleButton.pressedBackground = ToggleButton.background
ToggleButton.selectedBackground = ToggleButton.background
ToggleButton.disabledBackground = ToggleButton.background
ToggleButton.disabledSelectedBackground = ToggleButton.background
ToggleButton.toolbar.hoverBackground = ToggleButton.background
ToggleButton.toolbar.pressedBackground = ToggleButton.background
ToggleButton.toolbar.selectedBackground = ToggleButton.background
ToggleButton.tab.hoverBackground = null

View File

@@ -381,6 +381,9 @@ MenuBar.highlight
MenuBar.hoverBackground
MenuBar.itemMargins
MenuBar.shadow
MenuBar.underlineSelectionBackground
MenuBar.underlineSelectionColor
MenuBar.underlineSelectionHeight
MenuBar.windowBindings
MenuBarUI
MenuItem.acceleratorArrowGap
@@ -566,6 +569,7 @@ ScrollBar.minimumThumbSize
ScrollBar.pressedButtonBackground
ScrollBar.pressedThumbColor
ScrollBar.pressedThumbWithTrack
ScrollBar.pressedTrackColor
ScrollBar.showButtons
ScrollBar.squareButtons
ScrollBar.thumb
@@ -699,6 +703,8 @@ TabbedPane.labelShift
TabbedPane.light
TabbedPane.scrollButtonsPlacement
TabbedPane.scrollButtonsPolicy
TabbedPane.selectedBackground
TabbedPane.selectedForeground
TabbedPane.selectedLabelShift
TabbedPane.selectedTabPadInsets
TabbedPane.selectionFollowsFocus