Compare commits

..

32 Commits
0.16 ... 0.18

Author SHA1 Message Date
Karl Tauber
6572198178 release 0.18 2019-11-10 10:06:59 +01:00
Karl Tauber
f69b3f56dd ToolTip: use anti-aliasing to render multi-line tooltips 2019-11-10 00:09:51 +01:00
Karl Tauber
c379f2f3b0 JIDE: added missing dependency to flatlaf-testing project 2019-11-09 18:51:52 +01:00
Karl Tauber
e7194e43b4 JIDE: README.md added and publishing added to build.gradle.kts 2019-11-09 18:44:31 +01:00
Karl Tauber
883b282cd8 JIDE: JideTabbedPane: hover tab event if mouse is over close button
unfortunately it is not possible to replace JIDEs arrow and close buttons with own implementations
2019-11-09 18:21:25 +01:00
Karl Tauber
7c2b2d7f26 JIDE: basic JideTabbedPane implementation 2019-11-09 17:23:55 +01:00
Karl Tauber
08f525de5f TabbedPane: content pane is no longer opaque and use antialiasing for painting separator and content border 2019-11-09 15:53:02 +01:00
Karl Tauber
433659a5df TabbedPane: no longer modify BasicTabbedPaneUI.contentBorderInsets in getContentBorderInsets() because this is useless and confusing 2019-11-09 13:57:39 +01:00
Karl Tauber
7f50a30b29 TabbedPane: reworked painting in scroll-tab-layout, so that the separator line now spans the whole width and is no longer interrupted by the scroll buttons 2019-11-09 10:58:31 +01:00
Karl Tauber
d5944779e8 TabbedPane: use FlatClientProperties for JTabbedPane.hasFullBorder client property 2019-11-08 23:01:33 +01:00
Karl Tauber
fdaea31475 JIDE: flatlaf-jide-oss subproject created 2019-11-08 15:51:28 +01:00
Karl Tauber
a66ebd29b4 update to Gradle 5.6.4
./gradlew wrapper --gradle-version=5.6.4
2019-11-07 18:24:33 +01:00
Karl Tauber
f3006467e9 TextField and TextArea: do not apply minimum width if columns property > 0 2019-10-30 15:14:23 +01:00
Karl Tauber
aa52af4c8f added FlatLaf.isDark() 2019-10-29 11:01:48 +01:00
Karl Tauber
2e0fde464d release 0.17 2019-10-27 12:29:12 +01:00
Karl Tauber
9bf0124950 FlatBorder: replaced Paint with Color 2019-10-27 12:27:31 +01:00
Karl Tauber
eaa6db1d19 Table: fixed missing upper right corner (e.g. in SwingX JXTable with column control visible) 2019-10-27 12:25:39 +01:00
Karl Tauber
2ec142f000 Button: hover and pressed background colors are now derived from actual button background color (issue #21) 2019-10-27 11:03:40 +01:00
Karl Tauber
ec572436a9 extracted properties file parsing to new class UIDefaultsLoader 2019-10-25 23:07:44 +02:00
Karl Tauber
6e5e548c9d Testing: fixed content panel insets and removed 5,5 gaps 2019-10-25 10:44:24 +02:00
Karl Tauber
61c3bbad60 ComboBox and Spinner:
- make child components explicitly non-opaque
- paint parent background only if necessary
2019-10-25 10:28:24 +02:00
Karl Tauber
bc10c4e871 Made JComboBox, JProgressBar, JSpinner and JXDatePicker non-opaque.
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
an outside focus border (e.g. IntelliJ and Darcula themes).
(issues #20 and #17)
2019-10-25 10:28:18 +02:00
Karl Tauber
8b8d84c2a3 TextField and PasswordField: reduced duplicate code 2019-10-24 20:47:31 +02:00
Karl Tauber
5743b5d59f CheckBox: removed accidentally checked in debug output 2019-10-24 18:07:22 +02:00
Karl Tauber
9450ba5e46 Extras: fixed link in README.md 2019-10-24 15:31:13 +02:00
Karl Tauber
cfcbf3e61c CheckBox:
- compute focus border arc based on Component.focusWidth
- allow specifying border arc in UI defaults (CheckBox.arc)
2019-10-24 14:28:50 +02:00
Karl Tauber
136481c110 Testing: added "opaque" checkbox to test apps 2019-10-24 12:44:16 +02:00
Karl Tauber
7f43b3003c TriStateCheckBox component added 2019-10-24 12:36:40 +02:00
Karl Tauber
1b0c2687c8 Testing: added "background" checkbox to test apps 2019-10-24 10:52:53 +02:00
Karl Tauber
aeb80f862b build.gradle.kts: depend task "assemble" on "sourcesJar" and "javadocJar" so that they are built on Travic CI to file problems early (previously those tasks were build only just before publishing) 2019-10-23 17:06:25 +02:00
Karl Tauber
1de367e19e moved testing applications from src/test to new project flatlaf-testing (part 2) 2019-10-23 16:44:39 +02:00
Karl Tauber
62895a602f moved testing applications from src/test to new project flatlaf-testing (part 1) 2019-10-23 16:44:19 +02:00
76 changed files with 3298 additions and 788 deletions

View File

@@ -1,6 +1,33 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 0.18
- TextField and TextArea: Do not apply minimum width if `columns` property is
greater than zero.
- TabbedPane: In scroll-tab-layout, the separator line now spans the whole width
and is no longer interrupted by the scroll buttons.
- TabbedPane: Content pane is no longer opaque. Use antialiasing for painting
separator and content border.
- ToolTip: Use anti-aliasing to render multi-line tooltips.
- JIDE Common Layer: Support `JideTabbedPane`.
## 0.17
- CheckBox: Support painting a third state (set client property
"JButton.selectedState" to "indeterminate").
- `TriStateCheckBox` component added (see [FlatLaf Extras](flatlaf-extras)).
- Made `JComboBox`, `JProgressBar`, `JSpinner` and `JXDatePicker` non-opaque.
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
an outside focus border (e.g. IntelliJ and Darcula themes). (issues #20 and
#17)
- Button: Hover and pressed background colors are now derived from actual button
background color. (issue #21)
- Table: Fixed missing upper right corner (e.g. in SwingX JXTable with column
control visible).
## 0.16 ## 0.16
- Made some fixes for right-to-left support in ComboBox, Slider and ToolTip. - Made some fixes for right-to-left support in ComboBox, Slider and ToolTip.

View File

@@ -35,7 +35,7 @@ build script:
groupId: com.formdev groupId: com.formdev
artifactId: flatlaf artifactId: flatlaf
version: 0.16 version: 0.18
Otherwise download `flatlaf-<version>.jar` here: Otherwise download `flatlaf-<version>.jar` here:
@@ -46,6 +46,7 @@ Addons
------ ------
- [SwingX](flatlaf-swingx) - [SwingX](flatlaf-swingx)
- [JIDE Common Layer](https://github.com/jidesoft/jide-oss)
Documentation Documentation

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
version = "0.16" version = "0.18"
allprojects { allprojects {
repositories { repositories {

View File

@@ -34,17 +34,19 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
} }
} }
dependencies {
testImplementation( "com.miglayout:miglayout-swing:5.2" )
testImplementation( "com.jgoodies:jgoodies-forms:1.9.0" )
}
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
tasks { tasks {
assemble {
dependsOn(
"sourcesJar",
"javadocJar"
)
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) { if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
named<JavaCompile>( "compileModuleInfoJava" ) { named<JavaCompile>( "compileModuleInfoJava" ) {
sourceCompatibility = "9" sourceCompatibility = "9"
@@ -88,19 +90,6 @@ tasks {
from( javadoc ) from( javadoc )
} }
register( "testJar", Jar::class ) {
archiveBaseName.set( "flatlaf-test" )
from( sourceSets.test.get().output )
}
}
configurations {
create( "testArtifacts" )
}
artifacts {
add( "testArtifacts", tasks.getByPath( "testJar" ) )
} }
publishing { publishing {

View File

@@ -27,6 +27,11 @@ public interface FlatClientProperties
String BUTTON_TYPE = "JButton.buttonType"; String BUTTON_TYPE = "JButton.buttonType";
String BUTTON_TYPE_HELP = "help"; String BUTTON_TYPE_HELP = "help";
String SELECTED_STATE = "JButton.selectedState";
String SELECTED_STATE_INDETERMINATE = "indeterminate";
String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder";
/** /**
* Checks whether a client property of a component has the given value. * Checks whether a client property of a component has the given value.
*/ */

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a dark color scheme and looks like Darcula LaF. * A Flat LaF that has a dark color scheme and looks like Darcula LaF.
* *
* The UI defaults are loaded from FlatDarculaLaf.properties, FlatDarkLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatDarculaLaf public class FlatDarculaLaf

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a dark color scheme. * A Flat LaF that has a dark color scheme.
* *
* The UI defaults are loaded from FlatDarkLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatDarkLaf public class FlatDarkLaf
@@ -37,4 +39,9 @@ public class FlatDarkLaf
public String getDescription() { public String getDescription() {
return "Flat Dark Look and Feel"; return "Flat Dark Look and Feel";
} }
@Override
public boolean isDark() {
return true;
}
} }

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF. * A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
* *
* The UI defaults are loaded from FlatIntelliJLaf.properties, FlatLightLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatIntelliJLaf public class FlatIntelliJLaf

View File

@@ -19,10 +19,8 @@ package com.formdev.flatlaf;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Font; import java.awt.Font;
import java.awt.Insets;
import java.awt.KeyEventPostProcessor; import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager; import java.awt.KeyboardFocusManager;
import java.awt.Toolkit; import java.awt.Toolkit;
@@ -30,16 +28,7 @@ import java.awt.Window;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Function;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
@@ -48,16 +37,9 @@ import javax.swing.SwingUtilities;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.ScaledNumber;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -69,13 +51,6 @@ import com.formdev.flatlaf.util.UIScale;
public abstract class FlatLaf public abstract class FlatLaf
extends BasicLookAndFeel extends BasicLookAndFeel
{ {
private static final String TYPE_PREFIX = "{";
private static final String TYPE_PREFIX_END = "}";
private static final String VARIABLE_PREFIX = "@";
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
private static final String OPTIONAL_PREFIX = "?";
private static final String GLOBAL_PREFIX = "*.";
private BasicLookAndFeel base; private BasicLookAndFeel base;
private String desktopPropertyName; private String desktopPropertyName;
@@ -99,6 +74,8 @@ public abstract class FlatLaf
return getName(); return getName();
} }
public abstract boolean isDark();
@Override @Override
public boolean isNativeLookAndFeel() { public boolean isNativeLookAndFeel() {
return true; return true;
@@ -209,7 +186,7 @@ public abstract class FlatLaf
Object aquaMenuBarUI = useScreenMenuBar ? defaults.get( "MenuBarUI" ) : null; Object aquaMenuBarUI = useScreenMenuBar ? defaults.get( "MenuBarUI" ) : null;
initFonts( defaults ); initFonts( defaults );
loadDefaultsFromProperties( defaults ); UIDefaultsLoader.loadDefaultsFromProperties( getClass(), defaults );
// use Aqua MenuBarUI if Mac screen menubar is enabled // use Aqua MenuBarUI if Mac screen menubar is enabled
if( useScreenMenuBar ) if( useScreenMenuBar )
@@ -254,291 +231,8 @@ public abstract class FlatLaf
defaults.put( "MenuItem.acceleratorFont", uiFont ); defaults.put( "MenuItem.acceleratorFont", uiFont );
} }
/**
* Load properties associated to Flat LaF classes and add to UI defaults.
*
* Each class that extend this class may have its own .properties file
* in the same package as the class. Properties from superclasses are loaded
* first to give subclasses a chance to override defaults.
* E.g. if running FlatDarkLaf, then the FlatLaf.properties is loaded first
* and FlatDarkLaf.properties loaded second.
*/
private void loadDefaultsFromProperties( UIDefaults defaults ) {
// determine classes in class hierarchy in reverse order
ArrayList<Class<?>> lafClasses = new ArrayList<>();
for( Class<?> lafClass = getClass();
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
try {
// load properties files
Properties properties = new Properties();
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
for( Class<?> lafClass : lafClasses ) {
// load core properties
String propertiesName = "/" + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
if( in != null )
properties.load( in );
}
// load properties from addons
for( FlatDefaultsAddon addon : addonLoader ) {
try( InputStream in = addon.getDefaults( lafClass ) ) {
if( in != null )
properties.load( in );
}
}
}
Function<String, String> resolver = value -> {
return resolveValue( properties, value );
};
// get globals, which override all other defaults that end with same suffix
HashMap<String, Object> globals = new HashMap<>();
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( !key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
}
// override UI defaults with globals
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).contains( "." ) ) {
String skey = (String) key;
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
Object globalValue = globals.get( globalKey );
if( globalValue != null )
defaults.put( key, globalValue );
}
}
// add non-global properties to UI defaults
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
defaults.put( key, parseValue( key, value, resolver ) );
}
} catch( IOException ex ) {
ex.printStackTrace();
}
}
private String resolveValue( Properties properties, String value ) {
if( !value.startsWith( VARIABLE_PREFIX ) )
return value;
if( value.startsWith( REF_PREFIX ) )
value = value.substring( REF_PREFIX.length() );
boolean optional = false;
if( value.startsWith( OPTIONAL_PREFIX ) ) {
value = value.substring( OPTIONAL_PREFIX.length() );
optional = true;
}
String newValue = properties.getProperty( value );
if( newValue == null ) {
if( optional )
return "null";
System.err.println( "variable or reference '" + value + "' not found" );
throw new IllegalArgumentException( value );
}
return resolveValue( properties, newValue );
}
private enum ValueType { UNKNOWN, STRING, INTEGER, BORDER, ICON, INSETS, SIZE, COLOR, SCALEDNUMBER }
private Object parseValue( String key, String value, Function<String, String> resolver ) {
value = value.trim();
// null, false, true
switch( value ) {
case "null": return null;
case "false": return false;
case "true": return true;
}
ValueType valueType = ValueType.UNKNOWN;
// check whether value type is specified in the value
if( value.startsWith( TYPE_PREFIX ) ) {
int end = value.indexOf( TYPE_PREFIX_END );
if( end != -1 ) {
try {
String typeStr = value.substring( TYPE_PREFIX.length(), end );
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
// remove type from value
value = value.substring( end + TYPE_PREFIX_END.length() );
} catch( IllegalArgumentException ex ) {
// ignore
}
}
}
// determine value type from key
if( valueType == ValueType.UNKNOWN ) {
if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
valueType = ValueType.BORDER;
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
valueType = ValueType.ICON;
else if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
valueType = ValueType.INSETS;
else if( key.endsWith( "Size" ) )
valueType = ValueType.SIZE;
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
valueType = ValueType.INTEGER;
}
// parse value
switch( valueType ) {
case STRING: return value;
case INTEGER: return parseInteger( value, true );
case BORDER: return parseBorder( value, resolver );
case ICON: return parseInstance( value );
case INSETS: return parseInsets( value );
case SIZE: return parseSize( value );
case COLOR: return parseColor( value, true );
case SCALEDNUMBER: return parseScaledNumber( value );
case UNKNOWN:
default:
// colors
ColorUIResource color = parseColor( value, false );
if( color != null )
return color;
// integer
Integer integer = parseInteger( value, false );
if( integer != null )
return integer;
// string
return value;
}
}
private Object parseBorder( String value, Function<String, String> resolver ) {
if( value.indexOf( ',' ) >= 0 ) {
// top,left,bottom,right[,lineColor]
List<String> parts = split( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() == 5)
? parseColor( resolver.apply( parts.get( 4 ) ), true )
: null;
return (LazyValue) t -> {
return (lineColor != null)
? new FlatLineBorder( insets, lineColor )
: new FlatEmptyBorder( insets );
};
} else
return parseInstance( value );
}
private Object parseInstance( String value ) {
return (LazyValue) t -> {
try {
return Class.forName( value ).newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
ex.printStackTrace();
return null;
}
};
}
private Insets parseInsets( String value ) {
List<String> numbers = split( value, ',' );
try {
return new InsetsUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ),
Integer.parseInt( numbers.get( 2 ) ),
Integer.parseInt( numbers.get( 3 ) ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid insets '" + value + "'" );
throw ex;
}
}
private Dimension parseSize( String value ) {
List<String> numbers = split( value, ',' );
try {
return new DimensionUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid size '" + value + "'" );
throw ex;
}
}
private ColorUIResource parseColor( String value, boolean reportError ) {
try {
int rgb = Integer.parseInt( value, 16 );
if( value.length() == 6 )
return new ColorUIResource( rgb );
if( value.length() == 8 )
return new ColorUIResource( new Color( rgb, true ) );
if( reportError )
throw new NumberFormatException( value );
} catch( NumberFormatException ex ) {
if( reportError ) {
System.err.println( "invalid color '" + value + "'" );
throw ex;
}
// not a color --> ignore
}
return null;
}
private Integer parseInteger( String value, boolean reportError ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
if( reportError ) {
System.err.println( "invalid integer '" + value + "'" );
throw ex;
}
}
return null;
}
private ScaledNumber parseScaledNumber( String value ) {
try {
return new ScaledNumber( Integer.parseInt( value ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid integer '" + value + "'" );
throw ex;
}
}
public static List<String> split( String str, char delim ) { public static List<String> split( String str, char delim ) {
ArrayList<String> strs = new ArrayList<>(); return UIDefaultsLoader.split( str, delim );
int delimIndex = str.indexOf( delim );
int index = 0;
while( delimIndex >= 0 ) {
strs.add( str.substring( index, delimIndex ) );
index = delimIndex + 1;
delimIndex = str.indexOf( delim, index );
}
strs.add( str.substring( index ) );
return strs;
} }
private static void reSetLookAndFeel() { private static void reSetLookAndFeel() {

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a light color scheme. * A Flat LaF that has a light color scheme.
* *
* The UI defaults are loaded from FlatLightLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatLightLaf public class FlatLightLaf
@@ -37,4 +39,9 @@ public class FlatLightLaf
public String getDescription() { public String getDescription() {
return "Flat Light Look and Feel"; return "Flat Light Look and Feel";
} }
@Override
public boolean isDark() {
return false;
}
} }

View File

@@ -0,0 +1,407 @@
/*
* 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;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Function;
import javax.swing.UIDefaults;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.InsetsUIResource;
import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.ScaledNumber;
/**
* Load UI defaults from properties files associated to Flat LaF classes and add to UI defaults.
*
* Each class that extend the LaF class may have its own .properties file
* in the same package as the class. Properties from superclasses are loaded
* first to give subclasses a chance to override defaults.
* E.g. if running FlatDarkLaf, then the FlatLaf.properties is loaded first
* and FlatDarkLaf.properties loaded second.
*
* @author Karl Tauber
*/
class UIDefaultsLoader
{
private static final String TYPE_PREFIX = "{";
private static final String TYPE_PREFIX_END = "}";
private static final String VARIABLE_PREFIX = "@";
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
private static final String OPTIONAL_PREFIX = "?";
private static final String GLOBAL_PREFIX = "*.";
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, UIDefaults defaults ) {
// determine classes in class hierarchy in reverse order
ArrayList<Class<?>> lafClasses = new ArrayList<>();
for( Class<?> lafClass = lookAndFeelClass;
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
try {
// load properties files
Properties properties = new Properties();
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
for( Class<?> lafClass : lafClasses ) {
// load core properties
String propertiesName = "/" + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
if( in != null )
properties.load( in );
}
// load properties from addons
for( FlatDefaultsAddon addon : addonLoader ) {
try( InputStream in = addon.getDefaults( lafClass ) ) {
if( in != null )
properties.load( in );
}
}
}
Function<String, String> resolver = value -> {
return resolveValue( properties, value );
};
// get globals, which override all other defaults that end with same suffix
HashMap<String, Object> globals = new HashMap<>();
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( !key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
try {
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex );
}
}
// override UI defaults with globals
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).contains( "." ) ) {
String skey = (String) key;
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
Object globalValue = globals.get( globalKey );
if( globalValue != null )
defaults.put( key, globalValue );
}
}
// add non-global properties to UI defaults
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
try {
defaults.put( key, parseValue( key, value, resolver ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex );
}
}
} catch( IOException ex ) {
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 ) {
if( !value.startsWith( VARIABLE_PREFIX ) )
return value;
if( value.startsWith( REF_PREFIX ) )
value = value.substring( REF_PREFIX.length() );
boolean optional = false;
if( value.startsWith( OPTIONAL_PREFIX ) ) {
value = value.substring( OPTIONAL_PREFIX.length() );
optional = true;
}
String newValue = properties.getProperty( value );
if( newValue == null ) {
if( optional )
return "null";
throw new IllegalArgumentException( "variable or reference '" + value + "' not found" );
}
return resolveValue( properties, newValue );
}
private enum ValueType { UNKNOWN, STRING, INTEGER, BORDER, ICON, INSETS, SIZE, COLOR, SCALEDNUMBER }
private static Object parseValue( String key, String value, Function<String, String> resolver ) {
value = value.trim();
// null, false, true
switch( value ) {
case "null": return null;
case "false": return false;
case "true": return true;
}
ValueType valueType = ValueType.UNKNOWN;
// check whether value type is specified in the value
if( value.startsWith( TYPE_PREFIX ) ) {
int end = value.indexOf( TYPE_PREFIX_END );
if( end != -1 ) {
try {
String typeStr = value.substring( TYPE_PREFIX.length(), end );
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
// remove type from value
value = value.substring( end + TYPE_PREFIX_END.length() );
} catch( IllegalArgumentException ex ) {
// ignore
}
}
}
// determine value type from key
if( valueType == ValueType.UNKNOWN ) {
if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
valueType = ValueType.BORDER;
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
valueType = ValueType.ICON;
else if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
valueType = ValueType.INSETS;
else if( key.endsWith( "Size" ) )
valueType = ValueType.SIZE;
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
valueType = ValueType.INTEGER;
}
// parse value
switch( valueType ) {
case STRING: return value;
case INTEGER: return parseInteger( value, true );
case BORDER: return parseBorder( value, resolver );
case ICON: return parseInstance( value );
case INSETS: return parseInsets( value );
case SIZE: return parseSize( value );
case COLOR: return parseColor( value, true );
case SCALEDNUMBER: return parseScaledNumber( value );
case UNKNOWN:
default:
// colors
ColorUIResource color = parseColor( value, false );
if( color != null )
return color;
// integer
Integer integer = parseInteger( value, false );
if( integer != null )
return integer;
// string
return value;
}
}
private static Object parseBorder( String value, Function<String, String> resolver ) {
if( value.indexOf( ',' ) >= 0 ) {
// top,left,bottom,right[,lineColor]
List<String> parts = split( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() == 5)
? parseColor( resolver.apply( parts.get( 4 ) ), true )
: null;
return (LazyValue) t -> {
return (lineColor != null)
? new FlatLineBorder( insets, lineColor )
: new FlatEmptyBorder( insets );
};
} else
return parseInstance( value );
}
private static Object parseInstance( String value ) {
return (LazyValue) t -> {
try {
return Class.forName( value ).newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
ex.printStackTrace();
return null;
}
};
}
private static Insets parseInsets( String value ) {
List<String> numbers = split( value, ',' );
try {
return new InsetsUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ),
Integer.parseInt( numbers.get( 2 ) ),
Integer.parseInt( numbers.get( 3 ) ) );
} catch( NumberFormatException ex ) {
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
}
}
private static Dimension parseSize( String value ) {
List<String> numbers = split( value, ',' );
try {
return new DimensionUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ) );
} catch( NumberFormatException ex ) {
throw new IllegalArgumentException( "invalid size '" + value + "'" );
}
}
private static ColorUIResource parseColor( String value, boolean reportError ) {
if( value.endsWith( ")" ) )
return parseColorFunctions( value, reportError );
try {
int rgb = Integer.parseInt( value, 16 );
if( value.length() == 6 )
return new ColorUIResource( rgb );
if( value.length() == 8 )
return new ColorUIResource( new Color( rgb, true ) );
if( reportError )
throw new NumberFormatException( value );
} catch( NumberFormatException ex ) {
if( reportError )
throw new IllegalArgumentException( "invalid color '" + value + "'" );
// not a color --> ignore
}
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 ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
if( reportError )
throw new NumberFormatException( "invalid integer '" + value + "'" );
}
return null;
}
private static ScaledNumber parseScaledNumber( String value ) {
try {
return new ScaledNumber( Integer.parseInt( value ) );
} catch( NumberFormatException ex ) {
throw new NumberFormatException( "invalid integer '" + value + "'" );
}
}
static List<String> split( String str, char delim ) {
ArrayList<String> strs = new ArrayList<>();
int delimIndex = str.indexOf( delim );
int index = 0;
while( delimIndex >= 0 ) {
strs.add( str.substring( index, delimIndex ) );
index = delimIndex + 1;
delimIndex = str.indexOf( delim, index );
}
strs.add( str.substring( index ) );
return strs;
}
}

View File

@@ -16,14 +16,18 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent;
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;
/** /**
* Icon for {@link javax.swing.JCheckBox}. * Icon for {@link javax.swing.JCheckBox}.
@@ -50,6 +54,7 @@ import com.formdev.flatlaf.ui.FlatButtonUI;
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional * @uiDefault CheckBox.icon.selectedPressedBackground Color optional
* @uiDefault CheckBox.icon.checkmarkColor Color * @uiDefault CheckBox.icon.checkmarkColor Color
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color * @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.arc int
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -58,6 +63,7 @@ public class FlatCheckBoxIcon
{ {
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" ); protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" ); protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" ); protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" ); protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" );
@@ -84,7 +90,8 @@ public class FlatCheckBoxIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
boolean selected = (c instanceof AbstractButton) ? ((AbstractButton)c).isSelected() : false; boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
// paint focused border // paint focused border
if( c.hasFocus() && focusWidth > 0 ) { if( c.hasFocus() && focusWidth > 0 ) {
@@ -102,33 +109,40 @@ 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
if( selected ) { if( selected || indeterminate ) {
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor ); g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor );
paintCheckmark( g2 ); if( indeterminate )
paintIndeterminate( g2 );
else
paintCheckmark( g2 );
} }
} }
protected void paintFocusBorder( Graphics2D g2 ) { protected void paintFocusBorder( Graphics2D g2 ) {
// the outline focus border is painted outside of the icon // the outline focus border is painted outside of the icon
int wh = ICON_SIZE - 1 + (focusWidth * 2); int wh = ICON_SIZE - 1 + (focusWidth * 2);
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, 8, 8 ); int arcwh = (arc + focusWidth) * 2;
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
} }
protected void paintBorder( Graphics2D g2 ) { protected void paintBorder( Graphics2D g2 ) {
g2.fillRoundRect( 1, 0, 14, 14, 4, 4 ); int arcwh = arc * 2;
g2.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
} }
protected void paintBackground( Graphics2D g2 ) { protected void paintBackground( Graphics2D g2 ) {
g2.fillRoundRect( 2, 1, 12, 12, 3, 3 ); int arcwh = (arc * 2) - 1;
g2.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
} }
protected void paintCheckmark( Graphics2D g2 ) { protected void paintCheckmark( Graphics2D g2 ) {
@@ -140,4 +154,8 @@ public class FlatCheckBoxIcon
g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g2.draw( path ); g2.draw( path );
} }
protected void paintIndeterminate( Graphics2D g2 ) {
g2.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
}
} }

View File

@@ -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

View File

@@ -23,7 +23,6 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.KeyboardFocusManager; import java.awt.KeyboardFocusManager;
import java.awt.Paint;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@@ -83,7 +82,7 @@ public class FlatBorder
getLineWidth() + scale( (float) innerFocusWidth ), arc ); getLineWidth() + scale( (float) innerFocusWidth ), arc );
} }
g2.setPaint( getBorderColor( c ) ); g2.setColor( getBorderColor( c ) );
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, borderWidth, arc ); FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, borderWidth, arc );
} finally { } finally {
g2.dispose(); g2.dispose();
@@ -94,7 +93,7 @@ public class FlatBorder
return focusColor; return focusColor;
} }
protected Paint getBorderColor( Component c ) { protected Color getBorderColor( Component c ) {
boolean enabled = c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable()); boolean enabled = c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable());
return enabled return enabled
? (isFocused( c ) ? focusedBorderColor : borderColor) ? (isFocused( c ) ? focusedBorderColor : borderColor)

View File

@@ -21,7 +21,6 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Paint;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
@@ -68,7 +67,7 @@ public class FlatButtonBorder
} }
@Override @Override
protected Paint getBorderColor( Component c ) { protected Color getBorderColor( Component c ) {
boolean def = FlatButtonUI.isDefaultButton( c ); boolean def = FlatButtonUI.isDefaultButton( c );
return FlatButtonUI.buttonStateColor( c, return FlatButtonUI.buttonStateColor( c,
def ? defaultBorderColor : borderColor, def ? defaultBorderColor : borderColor,

View File

@@ -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();

View File

@@ -41,6 +41,7 @@ import javax.swing.JComponent;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.ListCellRenderer; import javax.swing.ListCellRenderer;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.AbstractBorder; import javax.swing.border.AbstractBorder;
@@ -123,6 +124,8 @@ public class FlatComboBoxUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( comboBox, "opaque", false );
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" ); arc = UIManager.getInt( "Component.arc" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
@@ -209,7 +212,7 @@ public class FlatComboBoxUI
String propertyName = e.getPropertyName(); String propertyName = e.getPropertyName();
if( editor != null && if( editor != null &&
((source == comboBox && (propertyName == "background" || propertyName == "foreground")) || ((source == comboBox && propertyName == "foreground") ||
(source == editor && propertyName == "enabled")) ) (source == editor && propertyName == "enabled")) )
{ {
// fix editor component colors // fix editor component colors
@@ -239,6 +242,10 @@ public class FlatComboBoxUI
if( editor instanceof JTextComponent ) if( editor instanceof JTextComponent )
((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() ); ((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() );
// explicitly make non-opaque
if( editor instanceof JComponent )
((JComponent)editor).setOpaque( false );
editor.applyComponentOrientation( comboBox.getComponentOrientation() ); editor.applyComponentOrientation( comboBox.getComponentOrientation() );
updateEditorColors(); updateEditorColors();
@@ -249,7 +256,6 @@ public class FlatComboBoxUI
// is used, then the editor is updated after the combobox and the // is used, then the editor is updated after the combobox and the
// colors are again replaced with default colors // colors are again replaced with default colors
boolean enabled = editor.isEnabled(); boolean enabled = editor.isEnabled();
editor.setBackground( FlatUIUtils.nonUIResource( enabled ? comboBox.getBackground() : disabledBackground ) );
editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent) editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent)
? comboBox.getForeground() ? comboBox.getForeground()
: disabledForeground ) ); : disabledForeground ) );
@@ -271,44 +277,44 @@ public class FlatComboBoxUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth(); int width = c.getWidth();
int height = c.getHeight(); int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0; float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
int arrowX = arrowButton.getX(); int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth(); int arrowWidth = arrowButton.getWidth();
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground ); g2.setColor( enabled ? c.getBackground() : disabledBackground );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background
if( enabled ) {
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint arrow button background // paint vertical line between value and arrow button
if( enabled ) { if( comboBox.isEditable() ) {
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground ); g2.setColor( enabled ? borderColor : disabledBorderColor );
Shape oldClip = g2.getClip(); float lw = scale( 1f );
if( isLeftToRight ) float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.clipRect( arrowX, 0, width - arrowX, height ); g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
if( comboBox.isEditable() ) {
// paint vertical line between value and arrow button
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
}
} }
paint( g, c ); paint( g, c );

View File

@@ -19,15 +19,12 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.plaf.basic.BasicPasswordFieldUI;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
@@ -46,7 +43,7 @@ public class FlatPasswordFieldUI
protected int focusWidth; protected int focusWidth;
protected int minimumWidth; protected int minimumWidth;
private Handler handler; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI(); return new FlatPasswordFieldUI();
@@ -63,6 +60,8 @@ public class FlatPasswordFieldUI
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( getComponent(), focusWidth ); MigLayoutVisualPadding.install( getComponent(), focusWidth );
} }
@@ -77,41 +76,27 @@ public class FlatPasswordFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
getComponent().addFocusListener( getHandler() ); focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
getComponent().addFocusListener( focusListener );
} }
@Override @Override
protected void uninstallListeners() { protected void uninstallListeners() {
super.uninstallListeners(); super.uninstallListeners();
getComponent().removeFocusListener( getHandler() ); getComponent().removeFocusListener( focusListener );
focusListener = null;
handler = null;
} }
public Handler getHandler() { @Override
if( handler == null ) protected void paintSafely( Graphics g ) {
handler = new Handler(); FlatTextFieldUI.paintBackground( g, getComponent(), focusWidth );
return handler; super.paintSafely( g );
} }
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); // background is painted elsewhere
FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
g2.setColor( c.getBackground() );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0 );
} finally {
g2.dispose();
}
} }
@Override @Override
@@ -129,20 +114,4 @@ public class FlatPasswordFieldUI
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) ); size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
return size; return size;
} }
//---- class Handler ------------------------------------------------------
private class Handler
implements FocusListener
{
@Override
public void focusGained( FocusEvent e ) {
getComponent().repaint();
}
@Override
public void focusLost( FocusEvent e ) {
getComponent().repaint();
}
}
} }

View File

@@ -23,6 +23,7 @@ import java.awt.Insets;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI; import javax.swing.plaf.basic.BasicProgressBarUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -39,6 +40,13 @@ public class FlatProgressBarUI
return new FlatProgressBarUI(); return new FlatProgressBarUI();
} }
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installProperty( progressBar, "opaque", false );
}
@Override @Override
protected Dimension getPreferredInnerHorizontal() { protected Dimension getPreferredInnerHorizontal() {
return UIScale.scale( super.getPreferredInnerHorizontal() ); return UIScale.scale( super.getPreferredInnerHorizontal() );

View File

@@ -17,10 +17,8 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ContainerEvent; import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener; import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
@@ -29,10 +27,9 @@ import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JViewport; import javax.swing.JViewport;
import javax.swing.ScrollPaneLayout; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicScrollPaneUI; import javax.swing.plaf.basic.BasicScrollPaneUI;
/** /**
@@ -53,17 +50,14 @@ public class FlatScrollPaneUI
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
super.installUI( c ); super.installUI( c );
if( scrollpane.getLayout() instanceof UIResource ) int focusWidth = UIManager.getInt( "Component.focusWidth" );
scrollpane.setLayout( new FlatScrollPaneLayout() ); LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( scrollpane, UIManager.getInt( "Component.focusWidth" ) ); MigLayoutVisualPadding.install( scrollpane, focusWidth );
} }
@Override @Override
public void uninstallUI( JComponent c ) { public void uninstallUI( JComponent c ) {
if( scrollpane.getLayout() instanceof FlatScrollPaneLayout )
scrollpane.setLayout( new ScrollPaneLayout.UIResource() );
MigLayoutVisualPadding.uninstall( scrollpane ); MigLayoutVisualPadding.uninstall( scrollpane );
super.uninstallUI( c ); super.uninstallUI( c );
@@ -169,27 +163,4 @@ public class FlatScrollPaneUI
scrollpane.repaint(); scrollpane.repaint();
} }
} }
//---- class FlatScrollPaneLayout -----------------------------------------
private static class FlatScrollPaneLayout
extends ScrollPaneLayout
{
@Override
public void layoutContainer( Container parent ) {
super.layoutContainer( parent );
// increase height of vertical scroll bar so that it also fills the upper right corner
if( colHead != null && vsb != null && colHead.isVisible() && vsb.isVisible() ) {
Rectangle colHeadBounds = colHead.getBounds();
Rectangle vsbBounds = vsb.getBounds();
if( vsbBounds.y > colHeadBounds.y ) {
vsbBounds.height += (vsbBounds.y - colHeadBounds.y);
vsbBounds.y = colHeadBounds.y;
vsb.setBounds( vsbBounds );
}
}
}
}
} }

View File

@@ -35,6 +35,7 @@ import java.beans.PropertyChangeListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
@@ -88,6 +89,8 @@ public class FlatSpinnerUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( spinner, "opaque", false );
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" ); arc = UIManager.getInt( "Component.arc" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
@@ -152,6 +155,13 @@ public class FlatSpinnerUI
@Override @Override
protected JComponent createEditor() { protected JComponent createEditor() {
JComponent editor = super.createEditor(); JComponent editor = super.createEditor();
// explicitly make non-opaque
editor.setOpaque( false );
JTextField textField = getEditorTextField( editor );
if( textField != null )
textField.setOpaque( false );
updateEditorColors(); updateEditorColors();
return editor; return editor;
} }
@@ -183,8 +193,6 @@ public class FlatSpinnerUI
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
// is used, then the text field is updated after the spinner and the // is used, then the text field is updated after the spinner and the
// colors are again replaced with default colors // colors are again replaced with default colors
textField.setBackground( FlatUIUtils.nonUIResource( spinner.isEnabled()
? spinner.getBackground() : disabledBackground ) );
textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) ); textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) );
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) ); textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
} }
@@ -225,45 +233,45 @@ public class FlatSpinnerUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth(); int width = c.getWidth();
int height = c.getHeight(); int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0; float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
Component nextButton = getHandler().nextButton; Component nextButton = getHandler().nextButton;
int arrowX = nextButton.getX(); int arrowX = nextButton.getX();
int arrowWidth = nextButton.getWidth(); int arrowWidth = nextButton.getWidth();
boolean enabled = spinner.isEnabled(); boolean enabled = spinner.isEnabled();
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground ); g2.setColor( enabled ? c.getBackground() : disabledBackground );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow buttons background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
// paint arrow buttons background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow buttons
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
} }
// paint vertical line between value and arrow buttons
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
paint( g, c ); paint( g, c );
} }
@@ -370,7 +378,6 @@ public class FlatSpinnerUI
@Override @Override
public void propertyChange( PropertyChangeEvent e ) { public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case "background":
case "foreground": case "foreground":
case "enabled": case "enabled":
updateEditorColors(); updateEditorColors();

View File

@@ -17,12 +17,19 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.Color; import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import javax.swing.JButton; import javax.swing.JButton;
@@ -108,7 +115,6 @@ public class FlatTabbedPaneUI
tabAreaInsets = scale( tabAreaInsets ); tabAreaInsets = scale( tabAreaInsets );
tabHeight = scale( tabHeight ); tabHeight = scale( tabHeight );
tabSelectionHeight = scale( tabSelectionHeight ); tabSelectionHeight = scale( tabSelectionHeight );
contentSeparatorHeight = scale( contentSeparatorHeight );
MigLayoutVisualPadding.install( tabPane, null ); MigLayoutVisualPadding.install( tabPane, null );
} }
@@ -135,7 +141,7 @@ public class FlatTabbedPaneUI
public void propertyChange( PropertyChangeEvent e ) { public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); super.propertyChange( e );
if( "JTabbedPane.hasFullBorder".equals( e.getPropertyName() ) ) { if( TABBED_PANE_HAS_FULL_BORDER.equals( e.getPropertyName() ) ) {
tabPane.revalidate(); tabPane.revalidate();
tabPane.repaint(); tabPane.repaint();
} }
@@ -176,70 +182,45 @@ public class FlatTabbedPaneUI
@Override @Override
protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) { protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) {
return super.calculateTabWidth( tabPlacement, tabIndex, metrics ) - 3 // was added by superclass return super.calculateTabWidth( tabPlacement, tabIndex, metrics ) - 3 /* was added by superclass */;
+ (!isTopOrBottom( tabPlacement ) && isScrollTabLayout() ? contentSeparatorHeight : 0);
} }
@Override @Override
protected int calculateTabHeight( int tabPlacement, int tabIndex, int fontHeight ) { protected int calculateTabHeight( int tabPlacement, int tabIndex, int fontHeight ) {
return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, fontHeight ) - 2 /* was added by superclass */ ) return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, fontHeight ) - 2 /* was added by superclass */ );
+ (isTopOrBottom( tabPlacement ) && isScrollTabLayout() ? contentSeparatorHeight : 0);
} }
/** /**
* The content border insets are used to create a separator between tabs and content. * The content border insets are used to create a separator between tabs and content.
* Except in scroll tab policy, where the separator is painted in paintTabArea().
* If client property JTabbedPane.hasFullBorder is true, then the content border insets * If client property JTabbedPane.hasFullBorder is true, then the content border insets
* are also used for the border. * are also used for the border.
*/ */
@Override @Override
protected Insets getContentBorderInsets( int tabPlacement ) { protected Insets getContentBorderInsets( int tabPlacement ) {
boolean hasFullBorder = this.hasFullBorder || (tabPane.getClientProperty( "JTabbedPane.hasFullBorder" ) == Boolean.TRUE); boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = contentSeparatorHeight; int sh = scale( contentSeparatorHeight );
Insets insets = hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 ); Insets insets = hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 );
if( isScrollTabLayout() ) Insets contentBorderInsets = new Insets( 0, 0, 0, 0 );
insets.top = 0;
rotateInsets( insets, contentBorderInsets, tabPlacement ); rotateInsets( insets, contentBorderInsets, tabPlacement );
return contentBorderInsets; return contentBorderInsets;
} }
@Override @Override
protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) { protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) {
if( isScrollTabLayout() && !isTopOrBottom( tabPlacement ) ) { return 0;
float shift = contentSeparatorHeight / 2f;
return Math.round( tabPlacement == LEFT ? -shift : shift );
} else
return 0;
} }
@Override @Override
protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) { protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) {
if( isScrollTabLayout() && isTopOrBottom( tabPlacement ) ) { return 0;
float shift = contentSeparatorHeight / 2f;
return Math.round( tabPlacement == TOP ? -shift : shift );
} else
return 0;
} }
@Override @Override
protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex ) { public void update( Graphics g, JComponent c ) {
if( isScrollTabLayout() ) { FlatUIUtils.setRenderingHints( (Graphics2D) g );
// paint separator between tabs and content
Rectangle bounds = g.getClipBounds();
g.setColor( contentAreaColor );
if( tabPlacement == TOP || tabPlacement == BOTTOM ) { super.update( g, c );
int y = (tabPlacement == TOP) ? bounds.y + bounds.height - contentSeparatorHeight : bounds.y;
g.fillRect( bounds.x, y, bounds.x + bounds.width, contentSeparatorHeight );
} else {
int x = (tabPlacement == LEFT) ? bounds.x + bounds.width - contentSeparatorHeight : bounds.x;
g.fillRect( x, bounds.y, contentSeparatorHeight, bounds.y + bounds.height );
}
}
super.paintTabArea( g, tabPlacement, selectedIndex );
} }
@Override @Override
@@ -275,19 +256,6 @@ public class FlatTabbedPaneUI
protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) int x, int y, int w, int h, boolean isSelected )
{ {
if( isScrollTabLayout() ) {
// make tab bounds smaller for separator between tabs and content
if( tabPlacement == TOP || tabPlacement == BOTTOM ) {
if( tabPlacement == BOTTOM )
y += contentSeparatorHeight;
h -= contentSeparatorHeight;
} else {
if( tabPlacement == RIGHT )
x += contentSeparatorHeight;
w -= contentSeparatorHeight;
}
}
// paint tab background // paint tab background
boolean enabled = tabPane.isEnabled(); boolean enabled = tabPane.isEnabled();
g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex
@@ -302,8 +270,38 @@ public class FlatTabbedPaneUI
protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex, protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) int x, int y, int w, int h, boolean isSelected )
{ {
if( !isSelected ) if( isSelected )
return; paintTabSelection( g, tabPlacement, x, y, w, h );
}
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
// increase clip bounds in scroll-tab-layout to paint over the separator line
Rectangle clipBounds = isScrollTabLayout() ? g.getClipBounds() : null;
if( clipBounds != null ) {
Rectangle newClipBounds = new Rectangle( clipBounds );
int contentSeparatorHeight = scale( this.contentSeparatorHeight );
switch( tabPlacement ) {
case TOP:
default:
newClipBounds.height += contentSeparatorHeight;
break;
case BOTTOM:
newClipBounds.y -= contentSeparatorHeight;
newClipBounds.height += contentSeparatorHeight;
break;
case LEFT:
newClipBounds.width += contentSeparatorHeight;
break;
case RIGHT:
newClipBounds.x -= contentSeparatorHeight;
newClipBounds.width += contentSeparatorHeight;
break;
}
g.setClip( newClipBounds );
}
g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor ); g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor );
@@ -330,13 +328,16 @@ public class FlatTabbedPaneUI
g.fillRect( x - contentInsets.right, y, tabSelectionHeight, h ); g.fillRect( x - contentInsets.right, y, tabSelectionHeight, h );
break; break;
} }
if( clipBounds != null )
g.setClip( clipBounds );
} }
/** /**
* Actually does the nearly the same as super.paintContentBorder() but * Actually does the nearly the same as super.paintContentBorder() but
* - content pane is always opaque
* - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly * - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly
* - not invoking paintContentBorder*Edge() methods * - not invoking paintContentBorder*Edge() methods
* - repaint selection
*/ */
@Override @Override
protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) { protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) {
@@ -377,9 +378,34 @@ public class FlatTabbedPaneUI
h -= (y - insets.top); h -= (y - insets.top);
} }
// compute insets for separator or full border
boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = scale( contentSeparatorHeight * 100 ); // multiply by 100 because rotateInsets() does not use floats
Insets ci = new Insets( 0, 0, 0, 0 );
rotateInsets( hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 ), ci, tabPlacement );
// paint content area // paint content area
g.setColor( contentAreaColor ); g.setColor( contentAreaColor );
g.fillRect( x, y, w, h ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Rectangle2D.Float( x, y, w, h ), false );
path.append( new Rectangle2D.Float( x + (ci.left / 100f), y + (ci.top / 100f),
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
((Graphics2D)g).fill( path );
// repaint selection in scroll-tab-layout because it may be painted before
// the content border was painted (from BasicTabbedPaneUI$ScrollableTabPanel)
if( isScrollTabLayout() && selectedIndex >= 0 ) {
Component scrollableTabViewport = findComponentByClassName( tabPane,
BasicTabbedPaneUI.class.getName() + "$ScrollableTabViewport" );
if( scrollableTabViewport != null ) {
Rectangle tabRect = getTabBounds( tabPane, selectedIndex );
Shape oldClip = g.getClip();
g.setClip( scrollableTabViewport.getBounds() );
paintTabSelection( g, tabPlacement, tabRect.x, tabRect.y, tabRect.width, tabRect.height );
g.setClip( oldClip );
}
}
} }
@Override @Override
@@ -392,7 +418,17 @@ public class FlatTabbedPaneUI
return tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT; return tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
} }
private boolean isTopOrBottom( int tabPlacement ) { private Component findComponentByClassName( Container c, String className ) {
return tabPlacement == TOP || tabPlacement == BOTTOM; for( Component child : c.getComponents() ) {
if( className.equals( child.getClass().getName() ) )
return child;
if( child instanceof Container ) {
Component c2 = findComponentByClassName( (Container) child, className );
if( c2 != null )
return c2;
}
}
return null;
} }
} }

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
@@ -81,15 +82,19 @@ public class FlatTextAreaUI
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( super.getPreferredSize( c ) ); return applyMinimumWidth( super.getPreferredSize( c ), c );
} }
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( super.getMinimumSize( c ) ); return applyMinimumWidth( super.getMinimumSize( c ), c );
} }
private Dimension applyMinimumWidth( Dimension size ) { private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
// do not apply minimum width if JTextArea.columns is set
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
return size;
// Assume that text area is in a scroll pane (that displays the border) // Assume that text area is in a scroll pane (that displays the border)
// and subtract 1px border line width. // and subtract 1px border line width.
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding // Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding

View File

@@ -21,11 +21,12 @@ import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.plaf.basic.BasicTextFieldUI;
@@ -47,7 +48,7 @@ public class FlatTextFieldUI
protected int focusWidth; protected int focusWidth;
protected int minimumWidth; protected int minimumWidth;
private Handler handler; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextFieldUI(); return new FlatTextFieldUI();
@@ -60,6 +61,8 @@ public class FlatTextFieldUI
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( getComponent(), focusWidth ); MigLayoutVisualPadding.install( getComponent(), focusWidth );
} }
@@ -74,38 +77,51 @@ public class FlatTextFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
getComponent().addFocusListener( getHandler() ); focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
getComponent().addFocusListener( focusListener );
} }
@Override @Override
protected void uninstallListeners() { protected void uninstallListeners() {
super.uninstallListeners(); super.uninstallListeners();
getComponent().removeFocusListener( getHandler() ); getComponent().removeFocusListener( focusListener );
focusListener = null;
handler = null;
} }
public Handler getHandler() { @Override
if( handler == null ) protected void paintSafely( Graphics g ) {
handler = new Handler(); paintBackground( g, getComponent(), focusWidth );
return handler; super.paintSafely( g );
} }
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); // background is painted elsewhere
}
FlatUIUtils.paintParentBackground( g, c ); static void paintBackground( Graphics g, JTextComponent c, int focusWidth ) {
// do not paint background if:
// - not opaque and
// - border is not a flat border and
// - opaque was explicitly set (to false)
// (same behaviour as in AquaTextFieldUI)
if( !c.isOpaque() && !(c.getBorder() instanceof FlatBorder) && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
return;
// fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && focusWidth > 0 )
FlatUIUtils.paintParentBackground( g, c );
// paint background
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float fFocusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) focusWidth ) : 0;
g2.setColor( c.getBackground() ); g2.setColor( c.getBackground() );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0 ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), fFocusWidth, 0 );
} finally { } finally {
g2.dispose(); g2.dispose();
} }
@@ -122,6 +138,10 @@ public class FlatTextFieldUI
} }
private Dimension applyMinimumWidth( Dimension size, JComponent c ) { private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
// do not apply minimum width if JTextField.columns is set
if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 )
return size;
Container parent = c.getParent(); Container parent = c.getParent();
if( parent instanceof JComboBox || if( parent instanceof JComboBox ||
parent instanceof JSpinner || parent instanceof JSpinner ||
@@ -132,20 +152,4 @@ public class FlatTextFieldUI
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) ); size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
return size; return size;
} }
//---- class Handler ------------------------------------------------------
private class Handler
implements FocusListener
{
@Override
public void focusGained( FocusEvent e ) {
getComponent().repaint();
}
@Override
public void focusLost( FocusEvent e ) {
getComponent().repaint();
}
}
} }

View File

@@ -81,7 +81,7 @@ public class FlatToolTipUI
boolean leftToRight = (comp != null ? comp : c).getComponentOrientation().isLeftToRight(); boolean leftToRight = (comp != null ? comp : c).getComponentOrientation().isLeftToRight();
for( String line : lines ) { for( String line : lines ) {
y += lineHeight; y += lineHeight;
g.drawString( line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y ); FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
} }
} else } else
super.paint( g, c ); super.paint( g, c );

View File

@@ -26,6 +26,8 @@ import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Shape; import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
@@ -33,8 +35,10 @@ import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.swing.JComponent; import javax.swing.JComponent;
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;
@@ -69,6 +73,14 @@ public class FlatUIUtils
dim.height + insets.top + insets.bottom ); dim.height + insets.top + insets.bottom );
} }
public static Insets addInsets( Insets insets1, Insets insets2 ) {
return new Insets(
insets1.top + insets2.top,
insets1.left + insets2.left,
insets1.bottom + insets2.bottom,
insets1.right + insets2.right );
}
public static Color getUIColor( String key, int defaultColorRGB ) { public static Color getUIColor( String key, int defaultColorRGB ) {
Color color = UIManager.getColor( key ); Color color = UIManager.getColor( key );
return (color != null) ? color : new Color( defaultColorRGB ); return (color != null) ? color : new Color( defaultColorRGB );
@@ -101,6 +113,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.
*/ */
@@ -238,6 +256,22 @@ public class FlatUIUtils
} }
/** /**
* Draws the given string at the specified location using text properties
* and anti-aliasing hints from the provided component.
*
* Use this method instead of Graphics.drawString() for correct anti-aliasing.
*
* Replacement for SwingUtilities2.drawString()
*/
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y );
}
/**
* Draws the given string at the specified location underlining the specified
* character. The provided component is used to query text properties and
* anti-aliasing hints.
*
* Replacement for SwingUtilities2.drawStringUnderlineCharAt() * Replacement for SwingUtilities2.drawStringUnderlineCharAt()
*/ */
public static void drawStringUnderlineCharAt( JComponent c, Graphics g, public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
@@ -246,15 +280,23 @@ public class FlatUIUtils
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y ); JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
} }
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {
boolean oldOpaque = c.isOpaque();
LookAndFeel.installProperty( c, "opaque", !oldOpaque );
boolean explicitlySet = c.isOpaque() == oldOpaque;
LookAndFeel.installProperty( c, "opaque", oldOpaque );
return explicitlySet;
}
//---- class HoverListener ------------------------------------------------ //---- class HoverListener ------------------------------------------------
public static class HoverListener public static class HoverListener
extends MouseAdapter extends MouseAdapter
{ {
private final JComponent repaintComponent; private final Component repaintComponent;
private final Consumer<Boolean> hoverChanged; private final Consumer<Boolean> hoverChanged;
public HoverListener( JComponent repaintComponent, Consumer<Boolean> hoverChanged ) { public HoverListener( Component repaintComponent, Consumer<Boolean> hoverChanged ) {
this.repaintComponent = repaintComponent; this.repaintComponent = repaintComponent;
this.hoverChanged = hoverChanged; this.hoverChanged = hoverChanged;
} }
@@ -276,4 +318,26 @@ public class FlatUIUtils
repaintComponent.repaint(); repaintComponent.repaint();
} }
} }
//---- class RepaintFocusListener -----------------------------------------
public static class RepaintFocusListener
implements FocusListener
{
private final Component repaintComponent;
public RepaintFocusListener( Component repaintComponent ) {
this.repaintComponent = repaintComponent;
}
@Override
public void focusGained( FocusEvent e ) {
repaintComponent.repaint();
}
@Override
public void focusLost( FocusEvent e ) {
repaintComponent.repaint();
}
}
} }

View File

@@ -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;
}
}
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -77,6 +77,7 @@ Button.default.borderWidth=1
CheckBox.border=com.formdev.flatlaf.ui.FlatMarginBorder CheckBox.border=com.formdev.flatlaf.ui.FlatMarginBorder
CheckBox.icon=com.formdev.flatlaf.icons.FlatCheckBoxIcon CheckBox.icon=com.formdev.flatlaf.icons.FlatCheckBoxIcon
CheckBox.arc=2
CheckBox.margin=2,2,2,2 CheckBox.margin=2,2,2,2
CheckBox.iconTextGap=4 CheckBox.iconTextGap=4
CheckBox.rollover=true CheckBox.rollover=true
@@ -277,6 +278,7 @@ ScrollBar.width=10
ScrollPane.border=com.formdev.flatlaf.ui.FlatBorder ScrollPane.border=com.formdev.flatlaf.ui.FlatBorder
ScrollPane.background=@@ScrollBar.track ScrollPane.background=@@ScrollBar.track
ScrollPane.fillUpperCorner=true
#---- Separator ---- #---- Separator ----

View File

@@ -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

View File

@@ -24,8 +24,9 @@ import java.awt.image.BufferedImage;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.FlatDarkLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import com.kitfox.svg.app.beans.SVGIcon; import com.kitfox.svg.app.beans.SVGIcon;
@@ -129,6 +130,7 @@ public class ScaledSVGIcon
} }
private static void lafChanged() { private static void lafChanged() {
darkLaf = (UIManager.getLookAndFeel() instanceof FlatDarkLaf); LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
darkLaf = (lookAndFeel instanceof FlatLaf && ((FlatLaf)lookAndFeel).isDark());
} }
} }

View File

@@ -4,6 +4,7 @@
package com.formdev.flatlaf.demo; package com.formdev.flatlaf.demo;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER;
import java.awt.*; import java.awt.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*; import javax.swing.border.*;
@@ -30,10 +31,10 @@ class TabsPanel
private void hasFullBorderChanged() { private void hasFullBorderChanged() {
Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null; Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null;
tabbedPane1.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane1.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane2.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane2.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane3.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane3.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane4.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane4.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
} }
private void moreTabsChanged() { private void moreTabsChanged() {

13
flatlaf-extras/README.md Normal file
View File

@@ -0,0 +1,13 @@
FlatLaf Extras
==============
This sub-project provides some additional components and classes:
- [TriStateCheckBox](src/main/java/com/formdev/flatlaf/extras/TriStateCheckBox.java):
A tri-state check box.
Download
--------
Not yet available.

View File

@@ -0,0 +1,30 @@
/*
* 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.
*/
version = rootProject.version
plugins {
`java-library`
}
dependencies {
implementation( project( ":flatlaf-core" ) )
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -0,0 +1,107 @@
/*
* 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.extras;
import java.awt.event.ItemEvent;
import javax.swing.JCheckBox;
/**
* A tri-state check box.
*
* To display the third state, this component requires an LaF that supports painting
* the indeterminate state if client property {@code "JButton.selectedState"} has the
* value {@code "indeterminate"}.
*
* FlatLaf and Mac Aqua LaF support the third state.
*
* @author Karl Tauber
*/
public class TriStateCheckBox
extends JCheckBox
{
public enum State { INDETERMINATE, SELECTED, UNSELECTED }
private State state;
private boolean thirdStateEnabled = true;
public TriStateCheckBox() {
this( null );
}
public TriStateCheckBox( String text ) {
this( text, State.INDETERMINATE );
}
public TriStateCheckBox( String text, State initialState ) {
super( text );
setModel( new ToggleButtonModel() {
@Override
public boolean isSelected() {
return state != State.UNSELECTED;
}
@Override
public void setSelected( boolean b ) {
switch( state ) {
case INDETERMINATE: setState( State.SELECTED ); break;
case SELECTED: setState( State.UNSELECTED ); break;
case UNSELECTED: setState( thirdStateEnabled ? State.INDETERMINATE : State.SELECTED ); break;
}
fireStateChanged();
fireItemStateChanged( new ItemEvent( this, ItemEvent.ITEM_STATE_CHANGED, this,
isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED ) );
}
} );
setState( initialState );
}
public State getState() {
return state;
}
public void setState( State state ) {
if( this.state == state )
return;
State oldState = this.state;
this.state = state;
putClientProperty( "JButton.selectedState", state == State.INDETERMINATE ? "indeterminate" : null );
firePropertyChange( "state", oldState, state );
repaint();
}
public boolean isThirdStateEnabled() {
return thirdStateEnabled;
}
public void setThirdStateEnabled( boolean thirdStateEnabled ) {
this.thirdStateEnabled = thirdStateEnabled;
if( state == State.INDETERMINATE )
setState( State.UNSELECTED );
}
@Override
public void setSelected( boolean b ) {
setState( b ? State.SELECTED : State.UNSELECTED );
}
}

View File

@@ -0,0 +1,37 @@
FlatLaf addon for JIDE Common Layer
===================================
This addon for FlatLaf adds support for **some**
[JIDE Common Layer](https://github.com/jidesoft/jide-oss) components.
Following JIDE Common Layer components are currently supported by this addon:
- `JideTabbedPane`
**Note**: We have currently no plans to support additional components. If you're
a paid customer of JFormDesigner and need support for other components, email to
JFormDesigner support and ask for it. Otherwise, try to implement it yourself
and create a pull request.
Download
--------
FlatLaf for JIDE Common Layer binaries are available on **JCenter** and **Maven
Central**.
If you use Maven or Gradle, add a dependency with following coordinates to your
build script:
groupId: com.formdev
artifactId: flatlaf-jide-oss
version: 0.18
Otherwise download `flatlaf-jide-oss-<version>.jar` here:
[![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf-jide-oss/images/download.svg)](https://bintray.com/jformdesigner/flatlaf/flatlaf-jide-oss/_latestVersion)
You also need `flatlaf-<version>.jar`, which you can download here:
[![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf/images/download.svg)](https://bintray.com/jformdesigner/flatlaf/flatlaf/_latestVersion)

View File

@@ -0,0 +1,121 @@
/*
* 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.
*/
version = rootProject.version
plugins {
`java-library`
`maven-publish`
id( "com.jfrog.bintray" ) version "1.8.4"
}
dependencies {
implementation( project( ":flatlaf-core" ) )
implementation( "com.jidesoft:jide-oss:3.6.18" )
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks {
assemble {
dependsOn(
"sourcesJar",
"javadocJar"
)
}
javadoc {
options {
this as StandardJavadocDocletOptions
tags = listOf( "uiDefault", "clientProperty" )
}
isFailOnError = false
}
register( "sourcesJar", Jar::class ) {
archiveClassifier.set( "sources" )
from( sourceSets.main.get().allJava )
}
register( "javadocJar", Jar::class ) {
archiveClassifier.set( "javadoc" )
from( javadoc )
}
}
publishing {
publications {
create<MavenPublication>( "maven" ) {
artifactId = "flatlaf-jide-oss"
groupId = "com.formdev"
from( components["java"] )
artifact( tasks["sourcesJar"] )
artifact( tasks["javadocJar"] )
pom {
name.set( "FlatLaf addon for JIDE Common Layer" )
description.set( "Flat Look and Feel addon for JIDE Common Layer" )
url.set( "https://github.com/JFormDesigner/FlatLaf" )
licenses {
license {
name.set( "The Apache License, Version 2.0" )
url.set( "http://www.apache.org/licenses/LICENSE-2.0.txt" )
}
}
developers {
developer {
name.set( "Karl Tauber" )
organization.set( "FormDev Software GmbH" )
organizationUrl.set( "https://www.formdev.com/" )
}
}
scm {
url.set( "https://github.com/JFormDesigner/FlatLaf" )
}
}
}
}
}
bintray {
user = System.getenv( "BINTRAY_USER" ) ?: System.getProperty( "bintray.user" )
key = System.getenv( "BINTRAY_KEY" ) ?: System.getProperty( "bintray.key" )
setPublications( "maven" )
with( pkg ) {
repo = "flatlaf"
name = "flatlaf-jide-oss"
setLicenses( "Apache-2.0" )
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
with( version ) {
name = project.version.toString()
}
publish = true
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.jideoss;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.swing.UIDefaults;
import com.formdev.flatlaf.FlatDefaultsAddon;
import com.formdev.flatlaf.FlatLaf;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.plaf.LookAndFeelFactory.UIDefaultsCustomizer;
import com.jidesoft.plaf.LookAndFeelFactory.UIDefaultsInitializer;
/**
* JIDE Common Layer addon for FlatLaf.
*
* @author Karl Tauber
*/
public class FlatJideOssDefaultsAddon
extends FlatDefaultsAddon
{
/**
* Finds JIDE Common Layer addon .properties file for the given LaF class
* in the same package as this class.
*/
@Override
public InputStream getDefaults( Class<?> lafClass ) {
LookAndFeelFactory.registerDefaultInitializer( FlatLaf.class.getName(), FlatJideUIDefaultsCustomizer.class.getName() );
LookAndFeelFactory.registerDefaultCustomizer( FlatLaf.class.getName(), FlatJideUIDefaultsCustomizer.class.getName() );
Class<?> addonClass = this.getClass();
String propertiesName = "/" + addonClass.getPackage().getName().replace( '.', '/' )
+ '/' + lafClass.getSimpleName() + ".properties";
return addonClass.getResourceAsStream( propertiesName );
}
//---- class FlatJideUIDefaultsCustomizer ---------------------------------
/**
* Because JIDE overwrites our UI defaults (from properties files) with its
* own UI defaults, we have to first remember our UI defaults in the initializer
* (invoked before JIDE overwrites UI defaults) and then restore them in the customizer.
*/
public static class FlatJideUIDefaultsCustomizer
implements UIDefaultsInitializer, UIDefaultsCustomizer
{
private static HashMap<Object, Object> jideDefaults;
@Override
public void initialize( UIDefaults defaults ) {
jideDefaults = new HashMap<>();
for( Map.Entry<Object, Object> e : defaults.entrySet() ) {
Object key = e.getKey();
if( key instanceof String && ((String)key).startsWith( "Jide" ) )
jideDefaults.put( key, e.getValue() );
}
}
@Override
public void customize( UIDefaults defaults ) {
if( jideDefaults != null ) {
defaults.putAll( jideDefaults );
jideDefaults = null;
}
}
}
}

View File

@@ -0,0 +1,372 @@
/*
* 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.jideoss.ui;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER;
import static com.formdev.flatlaf.FlatClientProperties.clientPropertyEquals;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.jidesoft.plaf.UIDefaultsLookup;
import com.jidesoft.plaf.basic.BasicJideTabbedPaneUI;
import com.jidesoft.swing.JideTabbedPane;
/**
* Provides the Flat LaF UI delegate for {@link com.jidesoft.swing.JideTabbedPane}.
*
* @author Karl Tauber
*/
public class FlatJideTabbedPaneUI
extends BasicJideTabbedPaneUI
{
protected Color underlineColor;
protected Color disabledUnderlineColor;
protected Color hoverColor;
protected Color focusColor;
protected Color contentAreaColor;
protected int tabHeight;
protected int tabSelectionHeight;
protected int contentSeparatorHeight;
protected boolean hasFullBorder;
protected boolean tabsOverlapBorder;
public static ComponentUI createUI( JComponent c ) {
return new FlatJideTabbedPaneUI();
}
@Override
protected void installDefaults() {
super.installDefaults();
_background = UIDefaultsLookup.getColor( "JideTabbedPane.background" );
underlineColor = UIManager.getColor( "TabbedPane.underlineColor" );
disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" );
hoverColor = UIManager.getColor( "TabbedPane.hoverColor" );
focusColor = UIManager.getColor( "TabbedPane.focusColor" );
contentAreaColor = UIManager.getColor( "TabbedPane.contentAreaColor" );
tabHeight = UIManager.getInt( "TabbedPane.tabHeight" );
tabSelectionHeight = UIManager.getInt( "TabbedPane.tabSelectionHeight" );
contentSeparatorHeight = UIManager.getInt( "TabbedPane.contentSeparatorHeight" );
hasFullBorder = UIManager.getBoolean( "TabbedPane.hasFullBorder" );
tabsOverlapBorder = UIManager.getBoolean( "TabbedPane.tabsOverlapBorder" );
// scale
_textIconGap = scale( _textIconGap );
tabHeight = scale( tabHeight );
tabSelectionHeight = scale( tabSelectionHeight );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
underlineColor = null;
disabledUnderlineColor = null;
hoverColor = null;
focusColor = null;
contentAreaColor = null;
}
@Override
protected PropertyChangeListener createPropertyChangeListener() {
return new PropertyChangeHandler() {
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
String propertyName = e.getPropertyName();
if( JideTabbedPane.PROPERTY_SELECTED_INDEX.equals( propertyName ) ) {
repaintTab( (Integer) e.getOldValue() );
repaintTab( (Integer) e.getNewValue() );
} else if( FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER.equals( propertyName ) ) {
_tabPane.revalidate();
_tabPane.repaint();
}
}
};
}
private void repaintTab( int tabIndex ) {
if( tabIndex < 0 || tabIndex >= _tabPane.getTabCount() )
return;
Rectangle r = getTabBounds( _tabPane, tabIndex );
if( r != null )
_tabPane.repaint( r );
}
@Override
protected MouseListener createMouseListener() {
return new RolloverMouseHandler();
}
@Override
protected MouseMotionListener createMouseMotionListener() {
return new RolloverMouseMotionHandler();
}
@Override
protected int calculateTabHeight( int tabPlacement, int tabIndex, FontMetrics metrics ) {
return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, metrics ) );
}
@Override
protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) {
return Math.max( tabHeight, super.calculateTabWidth( tabPlacement, tabIndex, metrics ) );
}
@Override
protected Insets getTabInsets( int tabPlacement, int tabIndex ) {
return scale( super.getTabInsets( tabPlacement, tabIndex ) );
}
@Override
protected Insets getSelectedTabPadInsets( int tabPlacement ) {
return scale( super.getSelectedTabPadInsets( tabPlacement ) );
}
@Override
protected Insets getTabAreaInsets( int tabPlacement ) {
return scale( super.getTabAreaInsets( tabPlacement ) );
}
@Override
protected int getTabShape() {
return JideTabbedPane.SHAPE_BOX;
}
/**
* The content border insets are used to create a separator between tabs and content.
* If client property JTabbedPane.hasFullBorder is true, then the content border insets
* are also used for the border.
*/
@Override
protected Insets getContentBorderInsets( int tabPlacement ) {
return FlatUIUtils.addInsets( getContentBorderInsets0( tabPlacement ),
scale( super.getContentBorderInsets( tabPlacement ) ) );
}
private Insets getContentBorderInsets0( int tabPlacement ) {
boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( _tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = scale( contentSeparatorHeight );
Insets insets = hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 );
Insets contentBorderInsets = new Insets( 0, 0, 0, 0 );
rotateInsets( insets, contentBorderInsets, tabPlacement );
return contentBorderInsets;
}
@Override
public void update( Graphics g, JComponent c ) {
FlatUIUtils.setRenderingHints( (Graphics2D) g );
super.update( g, c );
}
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( g, c );
// must paint tab area after content border was painted
if( !scrollableTabLayoutEnabled() && _tabPane.getTabCount() > 0 )
paintTabArea( g, _tabPane.getTabPlacement(), _tabPane.getSelectedIndex(), c );
}
@Override
protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected )
{
// paint tab background
boolean enabled = _tabPane.isEnabled();
g.setColor( enabled && _tabPane.isEnabledAt( tabIndex ) &&
(_indexMouseOver == tabIndex || (_closeButtons != null && ((JideTabbedPane.NoFocusButton)_closeButtons[tabIndex]).isMouseOver()))
? hoverColor
: (enabled && isSelected && _tabPane.hasFocus()
? focusColor
: _tabPane.getBackgroundAt( tabIndex )) );
g.fillRect( x, y, w, h );
}
@Override
protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h,
boolean isSelected )
{
if( isSelected )
paintTabSelection( g, tabPlacement, x, y, w, h );
}
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
// increase clip bounds in scroll-tab-layout to paint over the separator line
Rectangle clipBounds = scrollableTabLayoutEnabled() ? g.getClipBounds() : null;
if( clipBounds != null ) {
Rectangle newClipBounds = new Rectangle( clipBounds );
int contentSeparatorHeight = scale( this.contentSeparatorHeight );
switch( tabPlacement ) {
case TOP:
default:
newClipBounds.height += contentSeparatorHeight;
break;
case BOTTOM:
newClipBounds.y -= contentSeparatorHeight;
newClipBounds.height += contentSeparatorHeight;
break;
case LEFT:
newClipBounds.width += contentSeparatorHeight;
break;
case RIGHT:
newClipBounds.x -= contentSeparatorHeight;
newClipBounds.width += contentSeparatorHeight;
break;
}
g.setClip( newClipBounds );
}
g.setColor( _tabPane.isEnabled() ? underlineColor : disabledUnderlineColor );
Insets contentInsets = getContentBorderInsets0( tabPlacement );
// paint underline selection
switch( tabPlacement ) {
case TOP:
default:
int sy = y + h + contentInsets.top - tabSelectionHeight;
g.fillRect( x, sy, w, tabSelectionHeight );
break;
case BOTTOM:
g.fillRect( x, y - contentInsets.bottom, w, tabSelectionHeight );
break;
case LEFT:
int sx = x + w + contentInsets.left - tabSelectionHeight;
g.fillRect( sx, y, tabSelectionHeight, h );
break;
case RIGHT:
g.fillRect( x - contentInsets.right, y, tabSelectionHeight, h );
break;
}
if( clipBounds != null )
g.setClip( clipBounds );
}
/**
* Actually does the nearly the same as super.paintContentBorder() but
* - not invoking paintContentBorder*Edge() methods
* - repaint selection
*/
@Override
protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) {
if( _tabPane.getTabCount() <= 0 )
return;
Insets insets = _tabPane.getInsets();
Insets tabAreaInsets = getTabAreaInsets( tabPlacement );
int x = insets.left;
int y = insets.top;
int w = _tabPane.getWidth() - insets.right - insets.left;
int h = _tabPane.getHeight() - insets.top - insets.bottom;
Dimension lsize = isTabLeadingComponentVisible() ? _tabLeadingComponent.getPreferredSize() : new Dimension();
Dimension tsize = isTabTrailingComponentVisible() ? _tabTrailingComponent.getPreferredSize() : new Dimension();
// remove tabs from bounds
switch( tabPlacement ) {
case LEFT:
x += Math.max( calculateTabAreaWidth( tabPlacement, _runCount, _maxTabWidth ),
Math.max( lsize.width, tsize.width ) );
if( tabsOverlapBorder )
x -= tabAreaInsets.right;
w -= (x - insets.left);
break;
case RIGHT:
w -= calculateTabAreaWidth( tabPlacement, _runCount, _maxTabWidth );
if( tabsOverlapBorder )
w += tabAreaInsets.left;
break;
case BOTTOM:
h -= calculateTabAreaHeight( tabPlacement, _runCount, _maxTabHeight );
if( tabsOverlapBorder )
h += tabAreaInsets.top;
break;
case TOP:
default:
y += Math.max( calculateTabAreaHeight( tabPlacement, _runCount, _maxTabHeight ),
Math.max( lsize.height, tsize.height ) );
if( tabsOverlapBorder )
y -= tabAreaInsets.bottom;
h -= (y - insets.top);
}
// compute insets for separator or full border
boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( _tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = scale( contentSeparatorHeight * 100 ); // multiply by 100 because rotateInsets() does not use floats
Insets ci = new Insets( 0, 0, 0, 0 );
rotateInsets( hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 ), ci, tabPlacement );
// paint content area
g.setColor( contentAreaColor );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Rectangle2D.Float( x, y, w, h ), false );
path.append( new Rectangle2D.Float( x + (ci.left / 100f), y + (ci.top / 100f),
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
((Graphics2D)g).fill( path );
// repaint selection in scroll-tab-layout because it may be painted before
// the content border was painted (from BasicTabbedPaneUI$ScrollableTabPanel)
if( scrollableTabLayoutEnabled() && selectedIndex >= 0 && _tabScroller != null && _tabScroller.viewport != null ) {
Rectangle tabRect = getTabBounds( _tabPane, selectedIndex );
Shape oldClip = g.getClip();
g.setClip( _tabScroller.viewport.getBounds() );
paintTabSelection( g, tabPlacement, tabRect.x, tabRect.y, tabRect.width, tabRect.height );
g.setClip( oldClip );
}
}
@Override
protected void paintFocusIndicator( Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex,
Rectangle iconRect, Rectangle textRect, boolean isSelected )
{
}
}

View File

@@ -0,0 +1 @@
com.formdev.flatlaf.jideoss.FlatJideOssDefaultsAddon

View File

@@ -0,0 +1,32 @@
#
# 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.
#
#---- UI delegates ----
JideTabbedPaneUI=com.formdev.flatlaf.jideoss.ui.FlatJideTabbedPaneUI
#---- JideTabbedPane ----
JideTabbedPane.background=@background
JideTabbedPane.foreground=@foreground
JideTabbedPane.tabAreaBackground=@background
JideTabbedPane.tabInsets=@@TabbedPane.tabInsets
JideTabbedPane.tabAreaInsets=@@TabbedPane.tabAreaInsets
JideTabbedPane.contentBorderInsets=0,0,0,0
JideTabbedPane.tabRunOverlay=@@TabbedPane.tabRunOverlay
JideTabbedPane.shadow=@@TabbedPane.shadow

View File

@@ -6,8 +6,8 @@ This addon for FlatLaf adds support for **some** widely used SwingX components.
Many SwingX components that do not use UI delegates (e.g. `JXButton`, `JXLabel`, Many SwingX components that do not use UI delegates (e.g. `JXButton`, `JXLabel`,
`JXList`, etc) work with FlatLaf without adaptation. `JXList`, etc) work with FlatLaf without adaptation.
Following SwingX components, which use UI delegates, are supported by this Following SwingX components, which use UI delegates, are currently supported by
addon: this addon:
- `JXBusyLabel` - `JXBusyLabel`
- `JXDatePicker` - `JXDatePicker`
@@ -32,7 +32,7 @@ build script:
groupId: com.formdev groupId: com.formdev
artifactId: flatlaf-swingx artifactId: flatlaf-swingx
version: 0.16 version: 0.18
Otherwise download `flatlaf-swingx-<version>.jar` here: Otherwise download `flatlaf-swingx-<version>.jar` here:

View File

@@ -25,10 +25,6 @@ plugins {
dependencies { dependencies {
implementation( project( ":flatlaf-core" ) ) implementation( project( ":flatlaf-core" ) )
implementation( "org.swinglabs.swingx:swingx-all:1.6.5-1" ) implementation( "org.swinglabs.swingx:swingx-all:1.6.5-1" )
testImplementation( project( ":flatlaf-core", "testArtifacts" ) )
testImplementation( "org.swinglabs.swingx:swingx-beaninfo:1.6.5-1" )
testImplementation( "com.miglayout:miglayout-swing:5.2" )
} }
java { java {
@@ -37,6 +33,12 @@ java {
} }
tasks { tasks {
assemble {
dependsOn(
"sourcesJar",
"javadocJar"
)
}
javadoc { javadoc {
options { options {

View File

@@ -28,8 +28,6 @@ import java.awt.Insets;
import java.awt.LayoutManager; import java.awt.LayoutManager;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Shape; import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.text.ParseException; import java.text.ParseException;
import java.util.Calendar; import java.util.Calendar;
@@ -105,6 +103,8 @@ public class FlatDatePickerUI
super.installUI( c ); super.installUI( c );
LookAndFeel.installProperty( datePicker, "opaque", false );
// hack JXDatePicker.TodayPanel colors // hack JXDatePicker.TodayPanel colors
// (there is no need to uninstall these changes because only UIResources are used, // (there is no need to uninstall these changes because only UIResources are used,
// which are automatically replaced when switching LaF) // which are automatically replaced when switching LaF)
@@ -159,18 +159,7 @@ public class FlatDatePickerUI
editor.setName( "dateField" ); editor.setName( "dateField" );
editor.setBorder( BorderFactory.createEmptyBorder() ); editor.setBorder( BorderFactory.createEmptyBorder() );
editor.setOpaque( false ); editor.setOpaque( false );
editor.addFocusListener( new FocusListener() { editor.addFocusListener( new FlatUIUtils.RepaintFocusListener( datePicker ) );
@Override
public void focusLost( FocusEvent e ) {
if( datePicker != null )
datePicker.repaint();
}
@Override
public void focusGained( FocusEvent e ) {
if( datePicker != null )
datePicker.repaint();
}
} );
return editor; return editor;
} }
@@ -230,44 +219,44 @@ public class FlatDatePickerUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth(); int width = c.getWidth();
int height = c.getHeight(); int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0; float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
int arrowX = popupButton.getX(); int arrowX = popupButton.getX();
int arrowWidth = popupButton.getWidth(); int arrowWidth = popupButton.getWidth();
boolean enabled = c.isEnabled(); boolean enabled = c.isEnabled();
boolean isLeftToRight = c.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = c.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground ); g2.setColor( enabled ? c.getBackground() : disabledBackground );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
// paint arrow button background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow button
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
} }
// paint vertical line between value and arrow button
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
paint( g, c ); paint( g, c );
} }

View File

@@ -0,0 +1,39 @@
/*
* 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.
*/
version = rootProject.version
plugins {
`java-library`
}
dependencies {
implementation( project( ":flatlaf-core" ) )
implementation( project( ":flatlaf-extras" ) )
implementation( project( ":flatlaf-swingx" ) )
implementation( project( ":flatlaf-jide-oss" ) )
implementation( "com.miglayout:miglayout-swing:5.2" )
implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
implementation( "org.swinglabs.swingx:swingx-all:1.6.5-1" )
implementation( "org.swinglabs.swingx:swingx-beaninfo:1.6.5-1" )
implementation( "com.jidesoft:jide-oss:3.6.18" )
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import javax.swing.*; import javax.swing.*;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -23,12 +23,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatChooserTest public class FlatChooserTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatChooserTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatChooserTest" );
frame.showFrame( new FlatChooserTest() ); frame.showFrame( FlatChooserTest::new );
} ); } );
} }
@@ -56,7 +56,7 @@ public class FlatChooserTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets dialog,hidemode 3",
// columns // columns
"[]" + "[]" +
"[]", "[]",

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][]" "$columnConstraints": "[][]"
"$rowConstraints": "[top][top][]" "$rowConstraints": "[top][top][]"
} ) { } ) {

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import javax.swing.*; import javax.swing.*;
import javax.swing.table.*; import javax.swing.table.*;
@@ -24,12 +24,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatComponents2Test public class FlatComponents2Test
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatComponents2Test" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatComponents2Test" );
frame.showFrame( new FlatComponents2Test() ); frame.showFrame( FlatComponents2Test::new );
} ); } );
} }
@@ -62,7 +62,7 @@ public class FlatComponents2Test
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets dialog,hidemode 3",
// columns // columns
"[]" + "[]" +
"[200]" + "[200]" +

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][200][200]" "$columnConstraints": "[][200][200]"
"$rowConstraints": "[][][][::200][::150]" "$rowConstraints": "[][][][::200][::150]"
} ) { } ) {

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import java.awt.*; import java.awt.*;
import javax.swing.*; import javax.swing.*;
@@ -25,12 +25,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatComponentsTest public class FlatComponentsTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatComponentsTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatComponentsTest" );
frame.showFrame( new FlatComponentsTest() ); frame.showFrame( FlatComponentsTest::new );
} ); } );
} }
@@ -178,7 +178,7 @@ public class FlatComponentsTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets dialog,hidemode 3",
// columns // columns
"[]" + "[]" +
"[]" + "[]" +
@@ -758,8 +758,9 @@ public class FlatComponentsTest
//======== panel3 ======== //======== panel3 ========
{ {
panel3.setOpaque(false);
panel3.setLayout(new MigLayout( panel3.setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets 0,hidemode 3",
// columns // columns
"[]", "[]",
// rows // rows
@@ -801,6 +802,7 @@ public class FlatComponentsTest
//======== panel2 ======== //======== panel2 ========
{ {
panel2.setBorder(new TitledBorder("TitledBorder")); panel2.setBorder(new TitledBorder("TitledBorder"));
panel2.setOpaque(false);
panel2.setLayout(new FlowLayout()); panel2.setLayout(new FlowLayout());
} }
add(panel2, "cell 3 16,grow"); add(panel2, "cell 3 16,grow");

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][][][][][]" "$columnConstraints": "[][][][][][]"
"$rowConstraints": "[][][][][][][][][][][][][][][][][][][][][][]" "$rowConstraints": "[][][][][][][][][][][][][][][][][][][][][][]"
} ) { } ) {
@@ -56,7 +56,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1" "value": "cell 2 1"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatComponentsTest$TestDefaultButton" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatComponentsTest$TestDefaultButton" ) {
name: "button5" name: "button5"
"text": "default" "text": "default"
"displayedMnemonicIndex": 0 "displayedMnemonicIndex": 0
@@ -713,9 +713,10 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[]" "$columnConstraints": "[]"
"$rowConstraints": "[][][]" "$rowConstraints": "[][][]"
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets 0,hidemode 3"
} ) { } ) {
name: "panel3" name: "panel3"
"opaque": false
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "label3" name: "label3"
"text": "<html>JLabel HTML<br>Sample <b>content</b><br> <u>text</u></html>" "text": "<html>JLabel HTML<br>Sample <b>content</b><br> <u>text</u></html>"
@@ -759,6 +760,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel2" name: "panel2"
"border": new javax.swing.border.TitledBorder( "TitledBorder" ) "border": new javax.swing.border.TitledBorder( "TitledBorder" )
"opaque": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 16,grow" "value": "cell 3 16,grow"
} ) } )

View File

@@ -2,8 +2,9 @@
* Created by JFormDesigner on Tue Aug 27 21:47:02 CEST 2019 * Created by JFormDesigner on Tue Aug 27 21:47:02 CEST 2019
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER;
import java.awt.*; import java.awt.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*; import javax.swing.border.*;
@@ -14,12 +15,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatContainerTest public class FlatContainerTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatContainerTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatContainerTest" );
frame.showFrame( new FlatContainerTest() ); frame.showFrame( FlatContainerTest::new );
} ); } );
} }
@@ -37,10 +38,10 @@ public class FlatContainerTest
private void hasFullBorderChanged() { private void hasFullBorderChanged() {
Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null; Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null;
tabbedPane1.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane1.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane2.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane2.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane3.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane3.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane4.putClientProperty( "JTabbedPane.hasFullBorder", hasFullBorder ); tabbedPane4.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
} }
private void moreTabsChanged() { private void moreTabsChanged() {
@@ -104,7 +105,7 @@ public class FlatContainerTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"insets 0,hidemode 3", "insets dialog,hidemode 3",
// columns // columns
"[grow,fill]", "[grow,fill]",
// rows // rows
@@ -112,6 +113,7 @@ public class FlatContainerTest
//======== panel9 ======== //======== panel9 ========
{ {
panel9.setOpaque(false);
panel9.setLayout(new FormLayout( panel9.setLayout(new FormLayout(
"70dlu:grow, $lcgap, 70dlu:grow", "70dlu:grow, $lcgap, 70dlu:grow",
"default, $lgap, fill:70dlu, $lgap, pref, 2*($lgap, fill:70dlu:grow), $lgap, pref")); "default, $lgap, fill:70dlu, $lgap, pref, 2*($lgap, fill:70dlu:grow), $lgap, pref"));
@@ -283,6 +285,7 @@ public class FlatContainerTest
//======== panel14 ======== //======== panel14 ========
{ {
panel14.setOpaque(false);
panel14.setLayout(new MigLayout( panel14.setLayout(new MigLayout(
"insets 0,hidemode 3", "insets 0,hidemode 3",
// columns // columns

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3" "$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[grow,fill]" "$columnConstraints": "[grow,fill]"
"$rowConstraints": "[grow,fill]" "$rowConstraints": "[grow,fill]"
} ) { } ) {
@@ -17,6 +17,7 @@ new FormModel {
"$rowSpecs": "default, linegap, fill:70dlu, linegap, pref, linegap, fill:70dlu:grow, linegap, fill:70dlu:grow, linegap, pref" "$rowSpecs": "default, linegap, fill:70dlu, linegap, pref, linegap, fill:70dlu:grow, linegap, fill:70dlu:grow, linegap, pref"
} ) { } ) {
name: "panel9" name: "panel9"
"opaque": false
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "splitPaneLabel" name: "splitPaneLabel"
"text": "JSplitPane:" "text": "JSplitPane:"
@@ -203,6 +204,7 @@ new FormModel {
"$rowConstraints": "[center]" "$rowConstraints": "[center]"
} ) { } ) {
name: "panel14" name: "panel14"
"opaque": false
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "moreTabsCheckBox" name: "moreTabsCheckBox"
"text": "more tabs" "text": "more tabs"

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
@@ -58,6 +58,7 @@ public class FlatInspector
private Component lastComponent; private Component lastComponent;
private int lastX; private int lastX;
private int lastY; private int lastY;
private boolean inspectParent;
private JComponent highlightFigure; private JComponent highlightFigure;
private JToolTip tip; private JToolTip tip;
@@ -70,6 +71,7 @@ public class FlatInspector
public void mouseMoved( MouseEvent e ) { public void mouseMoved( MouseEvent e ) {
lastX = e.getX(); lastX = e.getX();
lastY = e.getY(); lastY = e.getY();
inspectParent = e.isShiftDown();
inspect( lastX, lastY ); inspect( lastX, lastY );
} }
} ); } );
@@ -105,6 +107,8 @@ public class FlatInspector
private void inspect( int x, int y ) { private void inspect( int x, int y ) {
Container contentPane = rootPane.getContentPane(); Container contentPane = rootPane.getContentPane();
Component c = SwingUtilities.getDeepestComponentAt( contentPane, x, y ); Component c = SwingUtilities.getDeepestComponentAt( contentPane, x, y );
if( inspectParent && c != null && c != contentPane )
c = c.getParent();
if( c == contentPane || (c != null && c.getParent() == contentPane) ) if( c == contentPane || (c != null && c.getParent() == contentPane) )
c = null; c = null;
@@ -237,7 +241,8 @@ public class FlatInspector
} }
text += "Enabled: " + c.isEnabled() + '\n'; text += "Enabled: " + c.isEnabled() + '\n';
text += "Opaque: " + c.isOpaque() + '\n'; text += "Opaque: " + c.isOpaque() + (c instanceof JComponent &&
FlatUIUtils.hasOpaqueBeenExplicitlySet( (JComponent) c ) ? " EXPLICIT" : "") + '\n';
text += "Focusable: " + c.isFocusable() + '\n'; text += "Focusable: " + c.isFocusable() + '\n';
text += "Left-to-right: " + c.getComponentOrientation().isLeftToRight() + '\n'; text += "Left-to-right: " + c.getComponentOrientation().isLeftToRight() + '\n';
text += "Parent: " + c.getParent().getClass().getName(); text += "Parent: " + c.getParent().getClass().getName();

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import java.awt.Component; import java.awt.Component;
import java.awt.Container; import java.awt.Container;
@@ -26,12 +26,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenusTest public class FlatMenusTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatMenusTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatMenusTest" );
frame.showFrame( new FlatMenusTest() ); frame.showFrame( FlatMenusTest::new );
} ); } );
} }
@@ -103,7 +103,7 @@ public class FlatMenusTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets dialog,hidemode 3",
// columns // columns
"[125]" + "[125]" +
"[]" + "[]" +
@@ -155,8 +155,9 @@ public class FlatMenusTest
//======== panel1 ======== //======== panel1 ========
{ {
panel1.setOpaque(false);
panel1.setLayout(new MigLayout( panel1.setLayout(new MigLayout(
"insets 0,hidemode 3,gap 5 5,ltr", "ltr,insets 0,hidemode 3",
// columns // columns
"[125,left]" + "[125,left]" +
"[fill]", "[fill]",
@@ -213,8 +214,9 @@ public class FlatMenusTest
//======== panel2 ======== //======== panel2 ========
{ {
panel2.setOpaque(false);
panel2.setLayout(new MigLayout( panel2.setLayout(new MigLayout(
"insets 0,gap 5 5", "insets 0",
// columns // columns
"[fill]", "[fill]",
// rows // rows
@@ -253,8 +255,9 @@ public class FlatMenusTest
//======== panel3 ======== //======== panel3 ========
{ {
panel3.setOpaque(false);
panel3.setLayout(new MigLayout( panel3.setLayout(new MigLayout(
"insets 0,gap 5 5", "insets 0",
// columns // columns
"[fill]", "[fill]",
// rows // rows
@@ -292,8 +295,9 @@ public class FlatMenusTest
//======== panel4 ======== //======== panel4 ========
{ {
panel4.setOpaque(false);
panel4.setLayout(new MigLayout( panel4.setLayout(new MigLayout(
"insets 0,gap 5 5", "insets 0",
// columns // columns
"[fill]", "[fill]",
// rows // rows

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[125][][][][]" "$columnConstraints": "[125][][][][]"
"$rowConstraints": "[][top][][]" "$rowConstraints": "[][top][][]"
} ) { } ) {
@@ -50,9 +50,10 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[125,left][fill]" "$columnConstraints": "[125,left][fill]"
"$rowConstraints": "[][][][][]" "$rowConstraints": "[][][][][]"
"$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$layoutConstraints": "ltr,insets 0,hidemode 3"
} ) { } ) {
name: "panel1" name: "panel1"
"opaque": false
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "menuLabel" name: "menuLabel"
"text": "JMenu:" "text": "JMenu:"
@@ -121,9 +122,10 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[fill]"
"$rowConstraints": "[][][][][]" "$rowConstraints": "[][][][][]"
"$layoutConstraints": "insets 0,gap 5 5" "$layoutConstraints": "insets 0"
} ) { } ) {
name: "panel2" name: "panel2"
"opaque": false
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu2" name: "menu2"
"text": "disabled" "text": "disabled"
@@ -161,9 +163,10 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[fill]"
"$rowConstraints": "[][][][]" "$rowConstraints": "[][][][]"
"$layoutConstraints": "insets 0,gap 5 5" "$layoutConstraints": "insets 0"
} ) { } ) {
name: "panel3" name: "panel3"
"opaque": false
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu3" name: "menu3"
"text": "text" "text": "text"
@@ -201,9 +204,10 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[fill]"
"$rowConstraints": "[][][][]" "$rowConstraints": "[][][][]"
"$layoutConstraints": "insets 0,gap 5 5" "$layoutConstraints": "insets 0"
} ) { } ) {
name: "panel4" name: "panel4"
"opaque": false
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu4" name: "menu4"
"text": "text" "text": "text"

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
@@ -27,12 +27,12 @@ import net.miginfocom.swing.*;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatOptionPaneTest public class FlatOptionPaneTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatOptionPaneTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatOptionPaneTest" );
frame.showFrame( new FlatOptionPaneTest() ); frame.showFrame( FlatOptionPaneTest::new );
} ); } );
} }
@@ -90,7 +90,7 @@ public class FlatOptionPaneTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"flowy,ltr,insets 0,hidemode 3,gap 5 5", "flowy,ltr,insets dialog,hidemode 3",
// columns // columns
"[]" + "[]" +
"[]" + "[]" +

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "flowy,ltr,insets 0,hidemode 3,gap 5 5" "$layoutConstraints": "flowy,ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][][fill]" "$columnConstraints": "[][][fill]"
"$rowConstraints": "[top][top][top][top][top][top][top][top]" "$rowConstraints": "[top][top][top][top][top][top][top][top]"
} ) { } ) {
@@ -30,7 +30,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0" "value": "cell 1 0"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "plainShowDialogLabel" name: "plainShowDialogLabel"
"optionPane": new FormReference( "plainOptionPane" ) "optionPane": new FormReference( "plainOptionPane" )
"titleLabel": new FormReference( "plainLabel" ) "titleLabel": new FormReference( "plainLabel" )
@@ -60,7 +60,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1" "value": "cell 1 1"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "errorShowDialogLabel" name: "errorShowDialogLabel"
"titleLabel": new FormReference( "errorLabel" ) "titleLabel": new FormReference( "errorLabel" )
"optionPane": new FormReference( "errorOptionPane" ) "optionPane": new FormReference( "errorOptionPane" )
@@ -90,7 +90,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2" "value": "cell 1 2"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "informationShowDialogLabel" name: "informationShowDialogLabel"
"optionPane": new FormReference( "informationOptionPane" ) "optionPane": new FormReference( "informationOptionPane" )
"titleLabel": new FormReference( "informationLabel" ) "titleLabel": new FormReference( "informationLabel" )
@@ -120,7 +120,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3" "value": "cell 1 3"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "questionShowDialogLabel" name: "questionShowDialogLabel"
"optionPane": new FormReference( "questionOptionPane" ) "optionPane": new FormReference( "questionOptionPane" )
"titleLabel": new FormReference( "questionLabel" ) "titleLabel": new FormReference( "questionLabel" )
@@ -147,7 +147,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4" "value": "cell 1 4"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "warningShowDialogLabel" name: "warningShowDialogLabel"
"optionPane": new FormReference( "warningOptionPane" ) "optionPane": new FormReference( "warningOptionPane" )
"titleLabel": new FormReference( "warningLabel" ) "titleLabel": new FormReference( "warningLabel" )
@@ -174,7 +174,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5" "value": "cell 1 5"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "inputShowDialogLabel" name: "inputShowDialogLabel"
"optionPane": new FormReference( "inputOptionPane" ) "optionPane": new FormReference( "inputOptionPane" )
"titleLabel": new FormReference( "inputLabel" ) "titleLabel": new FormReference( "inputLabel" )
@@ -202,7 +202,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6" "value": "cell 1 6"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "inputIconShowDialogLabel" name: "inputIconShowDialogLabel"
"titleLabel": new FormReference( "inputIconLabel" ) "titleLabel": new FormReference( "inputIconLabel" )
"optionPane": new FormReference( "inputIconOptionPane" ) "optionPane": new FormReference( "inputIconOptionPane" )
@@ -230,7 +230,7 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7" "value": "cell 1 7"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.FlatOptionPaneTest$ShowDialogLinkLabel" ) { add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) {
name: "customShowDialogLabel" name: "customShowDialogLabel"
"optionPane": new FormReference( "customOptionPane" ) "optionPane": new FormReference( "customOptionPane" )
"titleLabel": new FormReference( "customLabel" ) "titleLabel": new FormReference( "customLabel" )
@@ -239,7 +239,7 @@ new FormModel {
} ) } )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 790, 840 ) "size": new java.awt.Dimension( 790, 920 )
} ) } )
} }
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import java.awt.*; import java.awt.*;
import java.awt.event.ComponentAdapter; import java.awt.event.ComponentAdapter;
@@ -23,11 +23,19 @@ import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel; import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.extras.*;
import com.formdev.flatlaf.extras.TriStateCheckBox.State;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -44,6 +52,7 @@ public class FlatTestFrame
private static final String KEY_SCALE_FACTOR = "scaleFactor"; private static final String KEY_SCALE_FACTOR = "scaleFactor";
private final String title; private final String title;
private Supplier<JComponent> contentFactory;
private JComponent content; private JComponent content;
private FlatInspector inspector; private FlatInspector inspector;
@@ -206,8 +215,9 @@ public class FlatTestFrame
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
} }
public void showFrame( JComponent content ) { public void showFrame( Supplier<JComponent> contentFactory ) {
this.content = content; this.contentFactory = contentFactory;
this.content = contentFactory.get();
contentPanel.getContentPane().add( content ); contentPanel.getContentPane().add( content );
pack(); pack();
@@ -297,7 +307,7 @@ public class FlatTestFrame
c.setBackground( explicit ? Color.orange : restoreColor ); c.setBackground( explicit ? Color.orange : restoreColor );
} else { } else {
c.setForeground( explicit ? Color.blue : restoreColor ); c.setForeground( explicit ? Color.blue : restoreColor );
c.setBackground( explicit ? Color.red : restoreColor ); c.setBackground( explicit ? Color.green : restoreColor );
} }
} ); } );
@@ -308,6 +318,14 @@ public class FlatTestFrame
} ); } );
} }
private void backgroundChanged() {
contentPanel.repaint();
}
boolean isPaintBackgroundPattern() {
return backgroundCheckBox.isSelected();
}
private void rightToLeftChanged() { private void rightToLeftChanged() {
ComponentOrientation orientation = rightToLeftCheckBox.isSelected() ComponentOrientation orientation = rightToLeftCheckBox.isSelected()
? ComponentOrientation.RIGHT_TO_LEFT ? ComponentOrientation.RIGHT_TO_LEFT
@@ -390,17 +408,48 @@ public class FlatTestFrame
} }
} }
private void opaqueChanged() {
State opaque = opaqueTriStateCheckBox.getState();
if( opaque == State.INDETERMINATE )
recreateContent();
else {
updateComponentsRecur( content, (c, type) -> {
if( c instanceof JComponent )
((JComponent)c).setOpaque( opaque == State.SELECTED );
} );
contentPanel.repaint();
}
}
private void recreateContent() {
contentPanel.getContentPane().remove( content );
content = contentFactory.get();
contentPanel.getContentPane().add( content );
if( rightToLeftCheckBox.isSelected() )
rightToLeftChanged();
if( !enabledCheckBox.isSelected() )
enabledChanged();
if( explicitColorsCheckBox.isSelected() )
explicitColorsChanged();
contentPanel.revalidate();
contentPanel.repaint();
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
dialogPane = new JPanel(); dialogPane = new JPanel();
contentPanel = new JRootPane(); contentPanel = new JRootPane();
buttonBar = new JPanel(); buttonBar = new JPanel();
lookAndFeelComboBox = new JComboBox<>(); lookAndFeelComboBox = new JComboBox<>();
explicitColorsCheckBox = new JCheckBox(); scaleFactorComboBox = new JComboBox<>();
rightToLeftCheckBox = new JCheckBox(); rightToLeftCheckBox = new JCheckBox();
enabledCheckBox = new JCheckBox(); enabledCheckBox = new JCheckBox();
inspectCheckBox = new JCheckBox(); inspectCheckBox = new JCheckBox();
scaleFactorComboBox = new JComboBox<>(); explicitColorsCheckBox = new JCheckBox();
backgroundCheckBox = new JCheckBox();
opaqueTriStateCheckBox = new TriStateCheckBox();
closeButton = new JButton(); closeButton = new JButton();
//======== this ======== //======== this ========
@@ -416,7 +465,7 @@ public class FlatTestFrame
{ {
Container contentPanelContentPane = contentPanel.getContentPane(); Container contentPanelContentPane = contentPanel.getContentPane();
contentPanelContentPane.setLayout(new MigLayout( contentPanelContentPane.setLayout(new MigLayout(
"insets dialog,hidemode 3", "insets 0,hidemode 3",
// columns // columns
"[grow,fill]", "[grow,fill]",
// rows // rows
@@ -435,6 +484,8 @@ public class FlatTestFrame
"[fill]" + "[fill]" +
"[fill]" + "[fill]" +
"[fill]" + "[fill]" +
"[fill]" +
"[fill]" +
"[grow,fill]" + "[grow,fill]" +
"[button,fill]", "[button,fill]",
// rows // rows
@@ -444,11 +495,23 @@ public class FlatTestFrame
lookAndFeelComboBox.addActionListener(e -> lookAndFeelChanged()); lookAndFeelComboBox.addActionListener(e -> lookAndFeelChanged());
buttonBar.add(lookAndFeelComboBox, "cell 0 0"); buttonBar.add(lookAndFeelComboBox, "cell 0 0");
//---- explicitColorsCheckBox ---- //---- scaleFactorComboBox ----
explicitColorsCheckBox.setText("explicit colors"); scaleFactorComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
explicitColorsCheckBox.setMnemonic('X'); "default",
explicitColorsCheckBox.addActionListener(e -> explicitColorsChanged()); "1",
buttonBar.add(explicitColorsCheckBox, "cell 1 0"); "1.25",
"1.5",
"1.75",
"2.0",
"2.25",
"2.5",
"3",
"3.5",
"4"
}));
scaleFactorComboBox.setMaximumRowCount(20);
scaleFactorComboBox.addActionListener(e -> scaleFactorChanged());
buttonBar.add(scaleFactorComboBox, "cell 1 0");
//---- rightToLeftCheckBox ---- //---- rightToLeftCheckBox ----
rightToLeftCheckBox.setText("right-to-left"); rightToLeftCheckBox.setText("right-to-left");
@@ -469,27 +532,27 @@ public class FlatTestFrame
inspectCheckBox.addActionListener(e -> inspectChanged()); inspectCheckBox.addActionListener(e -> inspectChanged());
buttonBar.add(inspectCheckBox, "cell 4 0"); buttonBar.add(inspectCheckBox, "cell 4 0");
//---- scaleFactorComboBox ---- //---- explicitColorsCheckBox ----
scaleFactorComboBox.setModel(new DefaultComboBoxModel<>(new String[] { explicitColorsCheckBox.setText("explicit colors");
"default", explicitColorsCheckBox.setMnemonic('X');
"1", explicitColorsCheckBox.addActionListener(e -> explicitColorsChanged());
"1.25", buttonBar.add(explicitColorsCheckBox, "cell 5 0");
"1.5",
"1.75", //---- backgroundCheckBox ----
"2.0", backgroundCheckBox.setText("background");
"2.25", backgroundCheckBox.setMnemonic('B');
"2.5", backgroundCheckBox.addActionListener(e -> backgroundChanged());
"3", buttonBar.add(backgroundCheckBox, "cell 6 0");
"3.5",
"4" //---- opaqueTriStateCheckBox ----
})); opaqueTriStateCheckBox.setText("opaque");
scaleFactorComboBox.setMaximumRowCount(20); opaqueTriStateCheckBox.setMnemonic('O');
scaleFactorComboBox.addActionListener(e -> scaleFactorChanged()); opaqueTriStateCheckBox.addActionListener(e -> opaqueChanged());
buttonBar.add(scaleFactorComboBox, "cell 5 0"); buttonBar.add(opaqueTriStateCheckBox, "cell 7 0");
//---- closeButton ---- //---- closeButton ----
closeButton.setText("Close"); closeButton.setText("Close");
buttonBar.add(closeButton, "cell 7 0"); buttonBar.add(closeButton, "cell 9 0");
} }
dialogPane.add(buttonBar, BorderLayout.SOUTH); dialogPane.add(buttonBar, BorderLayout.SOUTH);
} }
@@ -502,11 +565,13 @@ public class FlatTestFrame
private JRootPane contentPanel; private JRootPane contentPanel;
private JPanel buttonBar; private JPanel buttonBar;
private JComboBox<LafInfo> lookAndFeelComboBox; private JComboBox<LafInfo> lookAndFeelComboBox;
private JCheckBox explicitColorsCheckBox; private JComboBox<String> scaleFactorComboBox;
private JCheckBox rightToLeftCheckBox; private JCheckBox rightToLeftCheckBox;
private JCheckBox enabledCheckBox; private JCheckBox enabledCheckBox;
private JCheckBox inspectCheckBox; private JCheckBox inspectCheckBox;
private JComboBox<String> scaleFactorComboBox; private JCheckBox explicitColorsCheckBox;
private JCheckBox backgroundCheckBox;
private TriStateCheckBox opaqueTriStateCheckBox;
private JButton closeButton; private JButton closeButton;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables

View File

@@ -11,7 +11,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "dialogPane" name: "dialogPane"
add( new FormContainer( "javax.swing.JRootPane", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JRootPane", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3" "$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[grow,fill]" "$columnConstraints": "[grow,fill]"
"$rowConstraints": "[grow,fill]" "$rowConstraints": "[grow,fill]"
} ) { } ) {
@@ -21,7 +21,7 @@ new FormModel {
} ) } )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog" "$layoutConstraints": "insets dialog"
"$columnConstraints": "[fill][fill][fill][fill][fill][fill][grow,fill][button,fill]" "$columnConstraints": "[fill][fill][fill][fill][fill][fill][fill][fill][grow,fill][button,fill]"
"$rowSpecs": "[fill]" "$rowSpecs": "[fill]"
} ) { } ) {
name: "buttonBar" name: "buttonBar"
@@ -34,11 +34,27 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0" "value": "cell 0 0"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JComboBox" ) {
name: "explicitColorsCheckBox" name: "scaleFactorComboBox"
"text": "explicit colors" "model": new javax.swing.DefaultComboBoxModel {
"mnemonic": 88 selectedItem: "default"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "explicitColorsChanged", false ) ) addElement( "default" )
addElement( "1" )
addElement( "1.25" )
addElement( "1.5" )
addElement( "1.75" )
addElement( "2.0" )
addElement( "2.25" )
addElement( "2.5" )
addElement( "3" )
addElement( "3.5" )
addElement( "4" )
}
"maximumRowCount": 20
auxiliary() {
"JavaCodeGenerator.typeParameters": "String"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scaleFactorChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0" "value": "cell 1 0"
} ) } )
@@ -67,35 +83,35 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0" "value": "cell 4 0"
} ) } )
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "scaleFactorComboBox" name: "explicitColorsCheckBox"
"model": new javax.swing.DefaultComboBoxModel { "text": "explicit colors"
selectedItem: "default" "mnemonic": 88
addElement( "default" ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "explicitColorsChanged", false ) )
addElement( "1" )
addElement( "1.25" )
addElement( "1.5" )
addElement( "1.75" )
addElement( "2.0" )
addElement( "2.25" )
addElement( "2.5" )
addElement( "3" )
addElement( "3.5" )
addElement( "4" )
}
"maximumRowCount": 20
auxiliary() {
"JavaCodeGenerator.typeParameters": "String"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scaleFactorChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 0" "value": "cell 5 0"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "backgroundCheckBox"
"text": "background"
"mnemonic": 66
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "backgroundChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 6 0"
} )
add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) {
name: "opaqueTriStateCheckBox"
"text": "opaque"
"mnemonic": 79
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "opaqueChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 7 0"
} )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "closeButton" name: "closeButton"
"text": "Close" "text": "Close"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 7 0" "value": "cell 9 0"
} ) } )
}, new FormLayoutConstraints( class java.lang.String ) { }, new FormLayoutConstraints( class java.lang.String ) {
"value": "South" "value": "South"

View File

@@ -14,11 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf; package com.formdev.flatlaf.testing;
import com.formdev.flatlaf.FlatLaf;
/** /**
* A Flat LaF that has a test color scheme. * A Flat LaF that has a test color scheme.
* *
* The UI defaults are loaded from FlatTestLaf.properties and FlatLaf.properties
*
* Used to develop Flat LaF. * Used to develop Flat LaF.
* *
* @author Karl Tauber * @author Karl Tauber
@@ -35,4 +39,9 @@ public class FlatTestLaf
public String getDescription() { public String getDescription() {
return "Flat Test Look and Feel"; return "Flat Test Look and Feel";
} }
@Override
public boolean isDark() {
return false;
}
} }

View File

@@ -0,0 +1,57 @@
/*
* 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.testing;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* @author Karl Tauber
*/
public class FlatTestPanel
extends JPanel
{
@Override
protected void paintComponent( Graphics g ) {
int width = getWidth();
int height = getHeight();
g.setColor( super.getBackground() );
g.fillRect( 0, 0, width, height );
if( isPaintBackgroundPattern() ) {
g.setColor( Color.magenta );
for( int y = 0; y < height; y += 2 )
g.drawLine( 0, y, width - 1, y );
}
}
/**
* Overridden to see which components paint background with color from parent.
*/
@Override
public Color getBackground() {
return isPaintBackgroundPattern() ? Color.red : super.getBackground();
}
private boolean isPaintBackgroundPattern() {
FlatTestFrame frame = (FlatTestFrame) SwingUtilities.getAncestorOfClass( FlatTestFrame.class, this );
return frame != null && frame.isPaintBackgroundPattern();
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.testing.extras;
import javax.swing.*;
import com.formdev.flatlaf.extras.*;
import com.formdev.flatlaf.testing.*;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatExtrasTest
extends FlatTestPanel
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatExtrasTest" );
frame.showFrame( FlatExtrasTest::new );
} );
}
public FlatExtrasTest() {
initComponents();
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
triStateLabel2.setText( triStateCheckBox2.getState().toString() );
}
private void triStateCheckBox1Changed() {
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
}
private void triStateCheckBox2Changed() {
triStateLabel2.setText( triStateCheckBox2.getState().toString() );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
label1 = new JLabel();
triStateCheckBox1 = new TriStateCheckBox();
triStateLabel1 = new JLabel();
triStateCheckBox2 = new TriStateCheckBox();
triStateLabel2 = new JLabel();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]" +
"[]" +
"[left]",
// rows
"[]" +
"[]"));
//---- label1 ----
label1.setText("TriStateCheckBox:");
add(label1, "cell 0 0");
//---- triStateCheckBox1 ----
triStateCheckBox1.setText("three states");
triStateCheckBox1.addActionListener(e -> triStateCheckBox1Changed());
add(triStateCheckBox1, "cell 1 0");
//---- triStateLabel1 ----
triStateLabel1.setText("text");
add(triStateLabel1, "cell 2 0");
//---- triStateCheckBox2 ----
triStateCheckBox2.setText("third state disabled");
triStateCheckBox2.setThirdStateEnabled(false);
triStateCheckBox2.addActionListener(e -> triStateCheckBox2Changed());
add(triStateCheckBox2, "cell 1 1");
//---- triStateLabel2 ----
triStateLabel2.setText("text");
add(triStateLabel2, "cell 2 1");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JLabel label1;
private TriStateCheckBox triStateCheckBox1;
private JLabel triStateLabel1;
private TriStateCheckBox triStateCheckBox2;
private JLabel triStateLabel2;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,50 @@
JFDML JFormDesigner: "7.0.0.0.194" Java: "11.0.2" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][][left]"
"$rowConstraints": "[][]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "TriStateCheckBox:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) {
name: "triStateCheckBox1"
"text": "three states"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "triStateCheckBox1Changed", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "triStateLabel1"
"text": "text"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
} )
add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) {
name: "triStateCheckBox2"
"text": "third state disabled"
"thirdStateEnabled": false
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "triStateCheckBox2Changed", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "triStateLabel2"
"text": "text"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 400, 300 )
} )
}
}

View File

@@ -0,0 +1,294 @@
/*
* 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.testing.jideoss;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import com.formdev.flatlaf.testing.*;
import com.formdev.flatlaf.testing.FlatTestFrame;
import com.jgoodies.forms.layout.*;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.swing.*;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatJideOssTest
extends FlatTestPanel
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatJideOssTest" );
LookAndFeelFactory.installJideExtension();
frame.showFrame( FlatJideOssTest::new );
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
LookAndFeelFactory.installJideExtension();
}
} );
} );
}
FlatJideOssTest() {
initComponents();
}
private void tabScrollChanged() {
int tabLayoutPolicy = tabScrollCheckBox.isSelected() ? JTabbedPane.SCROLL_TAB_LAYOUT : JTabbedPane.WRAP_TAB_LAYOUT;
tabbedPane1.setTabLayoutPolicy( tabLayoutPolicy );
tabbedPane2.setTabLayoutPolicy( tabLayoutPolicy );
tabbedPane3.setTabLayoutPolicy( tabLayoutPolicy );
tabbedPane4.setTabLayoutPolicy( tabLayoutPolicy );
}
private void hasFullBorderChanged() {
Boolean hasFullBorder = hasFullBorderCheckBox.isSelected() ? true : null;
tabbedPane1.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane2.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane3.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
tabbedPane4.putClientProperty( TABBED_PANE_HAS_FULL_BORDER, hasFullBorder );
}
private void moreTabsChanged() {
boolean moreTabs = moreTabsCheckBox.isSelected();
addRemoveMoreTabs( tabbedPane1, moreTabs );
addRemoveMoreTabs( tabbedPane2, moreTabs );
addRemoveMoreTabs( tabbedPane3, moreTabs );
addRemoveMoreTabs( tabbedPane4, moreTabs );
}
private void addRemoveMoreTabs( JTabbedPane tabbedPane, boolean add ) {
if( add ) {
tabbedPane.addTab( "Tab 4", new JLabel( "tab 4" ) );
tabbedPane.addTab( "Tab 5", new JLabel( "tab 5" ) );
} else {
int tabCount = tabbedPane.getTabCount();
if( tabCount > 3 ) {
for( int i = 0; i < 2; i++ )
tabbedPane.removeTabAt( tabbedPane.getTabCount() - 1 );
}
}
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JPanel panel9 = new JPanel();
JLabel tabbedPaneLabel = new JLabel();
tabbedPane1 = new JideTabbedPane();
JPanel panel1 = new JPanel();
JLabel label1 = new JLabel();
JPanel panel2 = new JPanel();
JLabel label2 = new JLabel();
tabbedPane3 = new JideTabbedPane();
JPanel panel5 = new JPanel();
JLabel label5 = new JLabel();
JPanel panel6 = new JPanel();
JLabel label6 = new JLabel();
tabbedPane2 = new JideTabbedPane();
JPanel panel3 = new JPanel();
JLabel label3 = new JLabel();
JPanel panel4 = new JPanel();
JLabel label4 = new JLabel();
tabbedPane4 = new JideTabbedPane();
JPanel panel7 = new JPanel();
JLabel label7 = new JLabel();
JPanel panel8 = new JPanel();
JLabel label8 = new JLabel();
JPanel panel14 = new JPanel();
moreTabsCheckBox = new JCheckBox();
tabScrollCheckBox = new JCheckBox();
hasFullBorderCheckBox = new JCheckBox();
CellConstraints cc = new CellConstraints();
//======== this ========
setLayout(new MigLayout(
"insets dialog,hidemode 3",
// columns
"[grow,fill]",
// rows
"[grow,fill]"));
//======== panel9 ========
{
panel9.setOpaque(false);
panel9.setLayout(new FormLayout(
"70dlu:grow, $lcgap, 70dlu:grow",
"pref, 2*($lgap, fill:70dlu:grow), $lgap, pref"));
//---- tabbedPaneLabel ----
tabbedPaneLabel.setText("JideTabbedPane:");
panel9.add(tabbedPaneLabel, cc.xy(1, 1));
//======== tabbedPane1 ========
{
//======== panel1 ========
{
panel1.setLayout(new FlowLayout());
//---- label1 ----
label1.setText("TOP");
panel1.add(label1);
}
tabbedPane1.addTab("Tab 1", panel1);
//======== panel2 ========
{
panel2.setBorder(new LineBorder(Color.magenta));
panel2.setLayout(new FlowLayout());
}
tabbedPane1.addTab("Tab 2", panel2);
//---- label2 ----
label2.setText("text");
tabbedPane1.addTab("Tab 3", label2);
}
panel9.add(tabbedPane1, cc.xy(1, 3));
//======== tabbedPane3 ========
{
tabbedPane3.setTabPlacement(SwingConstants.LEFT);
//======== panel5 ========
{
panel5.setLayout(new FlowLayout());
//---- label5 ----
label5.setText("LEFT");
panel5.add(label5);
}
tabbedPane3.addTab("Tab 1", panel5);
//======== panel6 ========
{
panel6.setBorder(new LineBorder(Color.magenta));
panel6.setLayout(new FlowLayout());
}
tabbedPane3.addTab("Tab 2", panel6);
//---- label6 ----
label6.setText("text");
tabbedPane3.addTab("Tab 3", label6);
}
panel9.add(tabbedPane3, cc.xy(3, 3));
//======== tabbedPane2 ========
{
tabbedPane2.setTabPlacement(SwingConstants.BOTTOM);
//======== panel3 ========
{
panel3.setLayout(new FlowLayout());
//---- label3 ----
label3.setText("BOTTOM");
panel3.add(label3);
}
tabbedPane2.addTab("Tab 1", panel3);
//======== panel4 ========
{
panel4.setBorder(new LineBorder(Color.magenta));
panel4.setLayout(new FlowLayout());
}
tabbedPane2.addTab("Tab 2", panel4);
tabbedPane2.setEnabledAt(1, false);
//---- label4 ----
label4.setText("text");
tabbedPane2.addTab("Tab 3", label4);
}
panel9.add(tabbedPane2, cc.xy(1, 5));
//======== tabbedPane4 ========
{
tabbedPane4.setTabPlacement(SwingConstants.RIGHT);
//======== panel7 ========
{
panel7.setLayout(new FlowLayout());
//---- label7 ----
label7.setText("RIGHT");
panel7.add(label7);
}
tabbedPane4.addTab("Tab 1", panel7);
//======== panel8 ========
{
panel8.setBorder(new LineBorder(Color.magenta));
panel8.setLayout(new FlowLayout());
}
tabbedPane4.addTab("Tab 2", panel8);
//---- label8 ----
label8.setText("text");
tabbedPane4.addTab("Tab 3", label8);
}
panel9.add(tabbedPane4, cc.xy(3, 5));
//======== panel14 ========
{
panel14.setOpaque(false);
panel14.setLayout(new MigLayout(
"insets 0,hidemode 3",
// columns
"[]" +
"[]" +
"[]",
// rows
"[center]"));
//---- moreTabsCheckBox ----
moreTabsCheckBox.setText("more tabs");
moreTabsCheckBox.setMnemonic('M');
moreTabsCheckBox.addActionListener(e -> moreTabsChanged());
panel14.add(moreTabsCheckBox, "cell 0 0");
//---- tabScrollCheckBox ----
tabScrollCheckBox.setText("tabLayoutPolicy = SCROLL");
tabScrollCheckBox.setMnemonic('S');
tabScrollCheckBox.setSelected(true);
tabScrollCheckBox.addActionListener(e -> tabScrollChanged());
panel14.add(tabScrollCheckBox, "cell 1 0,alignx left,growx 0");
//---- hasFullBorderCheckBox ----
hasFullBorderCheckBox.setText("JTabbedPane.hasFullBorder");
hasFullBorderCheckBox.setMnemonic('F');
hasFullBorderCheckBox.addActionListener(e -> hasFullBorderChanged());
panel14.add(hasFullBorderCheckBox, "cell 2 0,alignx left,growx 0");
}
panel9.add(panel14, cc.xywh(1, 7, 3, 1));
}
add(panel9, "cell 0 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JideTabbedPane tabbedPane1;
private JideTabbedPane tabbedPane3;
private JideTabbedPane tabbedPane2;
private JideTabbedPane tabbedPane4;
private JCheckBox moreTabsCheckBox;
private JCheckBox tabScrollCheckBox;
private JCheckBox hasFullBorderCheckBox;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,203 @@
JFDML JFormDesigner: "7.0.0.0.194" Java: "11.0.2" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[grow,fill]"
"$rowConstraints": "[grow,fill]"
} ) {
name: "this"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class com.jgoodies.forms.layout.FormLayout ) {
"$columnSpecs": "70dlu:grow, labelcompgap, 70dlu:grow"
"$rowSpecs": "pref, linegap, fill:70dlu:grow, linegap, fill:70dlu:grow, linegap, pref"
} ) {
name: "panel9"
"opaque": false
add( new FormComponent( "javax.swing.JLabel" ) {
name: "tabbedPaneLabel"
"text": "JideTabbedPane:"
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridX": 1
} )
add( new FormContainer( "com.jidesoft.swing.JideTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
name: "tabbedPane1"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel1"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "TOP"
} )
}, new FormLayoutConstraints( null ) {
"title": "Tab 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel2"
"border": &LineBorder0 new javax.swing.border.LineBorder( sfield java.awt.Color magenta, 1, false )
}, new FormLayoutConstraints( null ) {
"title": "Tab 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label2"
"text": "text"
}, new FormLayoutConstraints( null ) {
"title": "Tab 3"
} )
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridX": 1
"gridY": 3
} )
add( new FormContainer( "com.jidesoft.swing.JideTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
name: "tabbedPane3"
"tabPlacement": 2
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel5"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label5"
"text": "LEFT"
} )
}, new FormLayoutConstraints( null ) {
"title": "Tab 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel6"
"border": #LineBorder0
}, new FormLayoutConstraints( null ) {
"title": "Tab 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label6"
"text": "text"
}, new FormLayoutConstraints( null ) {
"title": "Tab 3"
} )
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridX": 3
"gridY": 3
} )
add( new FormContainer( "com.jidesoft.swing.JideTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
name: "tabbedPane2"
"tabPlacement": 3
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel3"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label3"
"text": "BOTTOM"
} )
}, new FormLayoutConstraints( null ) {
"title": "Tab 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel4"
"border": #LineBorder0
}, new FormLayoutConstraints( null ) {
"title": "Tab 2"
"enabled": false
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label4"
"text": "text"
}, new FormLayoutConstraints( null ) {
"title": "Tab 3"
} )
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridY": 5
} )
add( new FormContainer( "com.jidesoft.swing.JideTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
name: "tabbedPane4"
"tabPlacement": 4
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel7"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label7"
"text": "RIGHT"
} )
}, new FormLayoutConstraints( null ) {
"title": "Tab 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "panel8"
"border": #LineBorder0
}, new FormLayoutConstraints( null ) {
"title": "Tab 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label8"
"text": "text"
}, new FormLayoutConstraints( null ) {
"title": "Tab 3"
} )
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridX": 3
"gridY": 5
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[][][]"
"$rowConstraints": "[center]"
} ) {
name: "panel14"
"opaque": false
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "moreTabsCheckBox"
"text": "more tabs"
"mnemonic": 77
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "moreTabsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "tabScrollCheckBox"
"text": "tabLayoutPolicy = SCROLL"
"mnemonic": 83
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tabScrollChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0,alignx left,growx 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "hasFullBorderCheckBox"
"text": "JTabbedPane.hasFullBorder"
"mnemonic": 70
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hasFullBorderChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0,alignx left,growx 0"
} )
}, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) {
"gridY": 7
"gridWidth": 3
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 500, 500 )
} )
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.testing.swingx;
import java.io.InputStream;
import com.formdev.flatlaf.FlatDefaultsAddon;
/**
* SwingX addon for FlatLaf for testing.
*
* @author Karl Tauber
*/
public class FlatSwingXDefaultsTestAddon
extends FlatDefaultsAddon
{
/**
* Finds SwingX addon .properties file for the given LaF class
* in the same package as this class.
*/
@Override
public InputStream getDefaults( Class<?> lafClass ) {
Class<?> addonClass = this.getClass();
String propertiesName = "/" + addonClass.getPackage().getName().replace( '.', '/' )
+ '/' + lafClass.getSimpleName() + ".properties";
return addonClass.getResourceAsStream( propertiesName );
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.formdev.flatlaf.swingx; package com.formdev.flatlaf.testing.swingx;
import java.awt.*; import java.awt.*;
import java.util.Calendar; import java.util.Calendar;
@@ -22,19 +22,20 @@ import java.util.Date;
import javax.swing.*; import javax.swing.*;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
import org.jdesktop.swingx.*; import org.jdesktop.swingx.*;
import com.formdev.flatlaf.FlatTestFrame; import com.formdev.flatlaf.testing.FlatTestFrame;
import com.formdev.flatlaf.testing.FlatTestPanel;
/** /**
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatSwingXTest public class FlatSwingXTest
extends JPanel extends FlatTestPanel
{ {
public static void main( String[] args ) { public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatSwingXTest" ); FlatTestFrame frame = FlatTestFrame.create( args, "FlatSwingXTest" );
frame.useApplyComponentOrientation = true; frame.useApplyComponentOrientation = true;
frame.showFrame( new FlatSwingXTest() ); frame.showFrame( FlatSwingXTest::new );
} ); } );
} }
@@ -102,7 +103,7 @@ public class FlatSwingXTest
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
"hidemode 3,ltr", "ltr,insets dialog,hidemode 3",
// columns // columns
"[left]" + "[left]" +
"[]" + "[]" +
@@ -199,7 +200,7 @@ public class FlatSwingXTest
//---- busyCheckBox ---- //---- busyCheckBox ----
busyCheckBox.setText("busy"); busyCheckBox.setText("busy");
busyCheckBox.setMnemonic('B'); busyCheckBox.setMnemonic('Y');
busyCheckBox.addActionListener(e -> busyChanged()); busyCheckBox.addActionListener(e -> busyChanged());
add(busyCheckBox, "cell 2 6"); add(busyCheckBox, "cell 2 6");

View File

@@ -6,8 +6,8 @@ new FormModel {
auxiliary() { auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true "JavaCodeGenerator.defaultVariableLocal": true
} }
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3,ltr" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left][][][fill]" "$columnConstraints": "[left][][][fill]"
"$rowConstraints": "[]0[][]0[][][][][]" "$rowConstraints": "[]0[][]0[][][][][]"
} ) { } ) {
@@ -144,7 +144,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "busyCheckBox" name: "busyCheckBox"
"text": "busy" "text": "busy"
"mnemonic": 66 "mnemonic": 89
auxiliary() { auxiliary() {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }

View File

@@ -0,0 +1 @@
com.formdev.flatlaf.testing.swingx.FlatSwingXDefaultsTestAddon

View File

@@ -17,6 +17,7 @@
#---- variables ---- #---- variables ----
@background=ccffcc @background=ccffcc
@foreground=ff0000
@selectionBackground=00aa00 @selectionBackground=00aa00
@selectionInactiveBackground=888888 @selectionInactiveBackground=888888
@selectionInactiveForeground=ffffff @selectionInactiveForeground=ffffff
@@ -29,7 +30,7 @@
#---- globals ---- #---- globals ----
*.background=@background *.background=@background
*.foreground=ff0000 *.foreground=@foreground
*.textBackground=ccffcc *.textBackground=ccffcc
*.textForeground=ff0000 *.textForeground=ff0000
*.caretForeground=0000ff *.caretForeground=0000ff

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -17,5 +17,8 @@
rootProject.name = "FlatLaf" rootProject.name = "FlatLaf"
include( "flatlaf-core" ) include( "flatlaf-core" )
include( "flatlaf-extras" )
include( "flatlaf-swingx" ) include( "flatlaf-swingx" )
include( "flatlaf-jide-oss" )
include( "flatlaf-demo" ) include( "flatlaf-demo" )
include( "flatlaf-testing" )