Compare commits

...

14 Commits
3.6.1 ... 3.6.2

Author SHA1 Message Date
Karl Tauber
36d5685f4c release 3.6.2 2025-10-10 09:13:22 +02:00
Karl Tauber
ddc8d6e29c README.md: new applications using FlatLaf:
- OpenRocket
- Warteschlangensimulator
- Nortantis
- QStudio
- Launch4j
2025-10-07 19:36:39 +02:00
Karl Tauber
119b4a922d fixed loading FlatLaf properties files in NetBeans (broken since commit again; issue #1026)
now using old implementation again (before commit 2ac7234c32), but if that does not find properties file, then fallback to new implementation from commit 2ac7234c32
2025-09-29 21:30:41 +02:00
Karl Tauber
5e4f00f0c8 GitHub Actions: build using Java 25 LTS 2025-09-23 16:15:08 +02:00
Karl Tauber
15cbf28a0d Popup: no longer reuse popup windows for menus to avoid immediately closing dialogs on ChromeOS (issue #1029)
added system property `flatlaf.reuseVisiblePopupWindow`
2025-09-20 12:51:50 +02:00
Karl Tauber
f8e53c9064 README.md:
- replaced maven badges with shields.io because maven-badges.herokuapp.com did not show latest version 3.6.1 (instead shows 3.6)
- also the link target search.maven.org does not show 3.6.1
- now link to central.sonatype.com, which seems to be the successor of search.maven.org
  https://central.sonatype.org/faq/what-happened-to-search-maven-org/
2025-09-10 14:48:27 +02:00
Karl Tauber
b3c9638e47 Popup: no longer use popup.show() for already visible popup window to avoid that inactive owner window becomes active (issue #1037) 2025-09-09 20:00:26 +02:00
Karl Tauber
d079741f94 Extras: FlatAnimatedLafChange: made transition smoother:
- use a single component in layered pane to paint new and old UI snapshots (previously used two components)
- the snapshot layer component is now opaque, which avoids that window component hierarchy is involved when painting snapshots
- snapshots are now painted immediately, which should result in a smoother transition
- changed animation resolution from 30ms to 16ms
2025-09-09 18:54:11 +02:00
Karl Tauber
c051ad5f72 macOS: fixed window "flashing" when switching from a light to a dark theme (or vice versa), especially when using animated theme changer 2025-09-09 17:30:43 +02:00
Karl Tauber
1ed7aeaa45 Tree: removed unused method parameter; reported by Error Prone in commit d388158de7 2025-09-08 14:11:16 +02:00
Karl Tauber
2ac7234c32 support loading FlatLaf properties files from named Java modules without the need to open that package in module-info.java (issue #1026) 2025-09-08 13:03:17 +02:00
Karl Tauber
6f63982054 load properties files using UTF-8 instead of ISO 8859-1 (issue #1031) 2025-09-06 12:45:40 +02:00
Karl Tauber
d388158de7 Tree and List: fixed painting of rounded drop backgrounds (issue #1023) 2025-09-06 00:15:11 +02:00
Karl Tauber
e7a766bf8f added SOPTIM as Gold sponsor 2025-07-18 16:14:59 +02:00
34 changed files with 458 additions and 140 deletions

View File

@@ -67,11 +67,10 @@ jobs:
- 8 - 8
- 17 # LTS - 17 # LTS
- 21 # LTS - 21 # LTS
- 23 # latest
toolchain: [""] toolchain: [""]
# include: include:
# - java: 21 - java: 21
# toolchain: 22 # latest toolchain: 25 # LTS
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@@ -1,6 +1,36 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 3.6.2
#### New features and improvements
- If using `FlatLaf.registerCustomDefaultsSource( "com.myapp.themes" )` and
named Java modules, it is no longer necessary to add `opens com.myapp.themes;`
to `module-info.java`. (issue #1026)
- Extras: Made animated theme change (class `FlatAnimatedLafChange`) smoother.
#### Fixed bugs
- Tree and List: Fixed painting of rounded drop backgrounds. (issue #1023)
- Popup: Showing tooltip in inactive window brought that window to front (made
it active) and potentially hid the previously active window. (issue #1037)
- Popup: No longer reuse popup windows for menus to avoid immediately closing
dialogs on ChromeOS. (issue #1029)
- macOS: Fixed window "flashing" when switching from a light to a dark theme (or
vice versa). Especially when using animated theme changer (see
[FlatLaf Extras](flatlaf-extras)).
#### Incompatibilities
- FlatLaf properties files are now loaded using the UTF-8 character encoding
instead of ISO 8859-1. In usual properties files you will not notice any
difference because they use only ASCII characters, but if you've put localized
(non-English) texts (e.g. German umlauts) into your properties files, you need
to convert them to UTF-8. Properties files created with the FlatLaf Theme
Editor already use UTF-8, including in older versions. (issue #1031)
## 3.6.1 ## 3.6.1
- Extras: Support JSVG 2.0.0. Minimum JSVG version is now 1.6.0. (issue #997) - Extras: Support JSVG 2.0.0. Minimum JSVG version is now 1.6.0. (issue #997)

View File

@@ -35,6 +35,8 @@ Sponsors
### Current Sponsors ### Current Sponsors
<a href="https://www.soptim.de/"><img src="https://www.formdev.com/flatlaf/sponsor/soptim.svg" width="200" alt="SOPTIM" title="SOPTIM - your expert in software solutions for the energy industry"></a>
&nbsp; &nbsp; &nbsp; &nbsp;
<a href="https://exocharts.com/"><img src="https://www.formdev.com/flatlaf/sponsor/Exocharts.png" width="200" alt="Exocharts" title="Exocharts - Professional Grade OrderFlow"></a> <a href="https://exocharts.com/"><img src="https://www.formdev.com/flatlaf/sponsor/Exocharts.png" width="200" alt="Exocharts" title="Exocharts - Professional Grade OrderFlow"></a>
<!-- [![None Sponsors](images/none-sponsors.png)](https://www.formdev.com/flatlaf/sponsor/) --> <!-- [![None Sponsors](images/none-sponsors.png)](https://www.formdev.com/flatlaf/sponsor/) -->
@@ -72,7 +74,7 @@ build script:
Otherwise, download `flatlaf-<version>.jar` here: Otherwise, download `flatlaf-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf)
See also See also
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/) [Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
@@ -194,6 +196,8 @@ Applications using FlatLaf
- ![New](images/new.svg) - ![New](images/new.svg)
[Zettelkasten](https://github.com/Zettelkasten-Team/Zettelkasten) - knowledge [Zettelkasten](https://github.com/Zettelkasten-Team/Zettelkasten) - knowledge
management tool management tool
- ![New](images/new.svg) [QStudio](https://www.timestored.com/qstudio/) - free
SQL editor
### Security ### Security
@@ -234,6 +238,8 @@ Applications using FlatLaf
mobile & web platform mobile & web platform
- ![New](images/new.svg) [EduMIPS64](https://github.com/EduMIPS64/edumips64) - - ![New](images/new.svg) [EduMIPS64](https://github.com/EduMIPS64/edumips64) -
visual MIPS64 CPU simulator visual MIPS64 CPU simulator
- ![New](images/new.svg) [Launch4j](https://launch4j.sourceforge.net/) -
cross-platform Java executable wrapper
### Electrical ### Electrical
@@ -279,9 +285,16 @@ Applications using FlatLaf
from any webnovel and lightnovel site from any webnovel and lightnovel site
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with - [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
ease ease
- ![New](images/new.svg) [Nortantis](https://jandjheydorn.com/nortantis) -
fantasy map generator and editor
### Modelling / Planning ### Modelling / Planning
- ![New](images/new.svg) [OpenRocket](https://github.com/openrocket/openrocket) -
model-rocketry aerodynamics and trajectory simulation software
- ![New](images/new.svg)
[Warteschlangensimulator](https://github.com/A-Herzog/Warteschlangensimulator) -
discrete-event stochastic simulator
- ![New](images/new.svg) [Gephi](https://github.com/gephi/gephi) - the Open - ![New](images/new.svg) [Gephi](https://github.com/gephi/gephi) - the Open
Graph Viz Platform Graph Viz Platform
- [Astah](https://astah.net/) (**commercial**) - create UML, ER Diagram, - [Astah](https://astah.net/) (**commercial**) - create UML, ER Diagram,

View File

@@ -1,5 +1,5 @@
#Signature file v4.1 #Signature file v4.1
#Version 3.6.1 #Version 3.6.2
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType" fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
@@ -297,6 +297,7 @@ CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties
fld public final static java.lang.String ANIMATION = "flatlaf.animation" fld public final static java.lang.String ANIMATION = "flatlaf.animation"
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded" fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath" fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
fld public final static java.lang.String REUSE_VISIBLE_POPUP_WINDOW = "flatlaf.reuseVisiblePopupWindow"
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale" fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown" fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled" fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"

View File

@@ -911,8 +911,7 @@ public abstract class FlatLaf
* <p> * <p>
* Invoke this method before setting the look and feel. * Invoke this method before setting the look and feel.
* <p> * <p>
* If using Java modules, the package must be opened in {@code module-info.java}. * If using Java modules, it is not necessary to open the package in {@code module-info.java}.
* Otherwise, use {@link #registerCustomDefaultsSource(URL)}.
* *
* @param packageName a package name (e.g. "com.myapp.resources") * @param packageName a package name (e.g. "com.myapp.resources")
*/ */
@@ -959,9 +958,9 @@ public abstract class FlatLaf
* <p> * <p>
* See {@link #registerCustomDefaultsSource(String)} for details. * See {@link #registerCustomDefaultsSource(String)} for details.
* <p> * <p>
* This method is useful if using Java modules and the package containing the properties files
* is not opened in {@code module-info.java}.
* E.g. {@code FlatLaf.registerCustomDefaultsSource( MyApp.class.getResource( "/com/myapp/themes/" ) )}. * E.g. {@code FlatLaf.registerCustomDefaultsSource( MyApp.class.getResource( "/com/myapp/themes/" ) )}.
* <p>
* If using Java modules, it is not necessary to open the package in {@code module-info.java}.
* *
* @param packageUrl a package URL * @param packageUrl a package URL
* @since 2 * @since 2

View File

@@ -20,6 +20,9 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Properties;
@@ -62,8 +65,8 @@ public class FlatPropertiesLaf
throws IOException throws IOException
{ {
Properties properties = new Properties(); Properties properties = new Properties();
try( InputStream in2 = in ) { try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 )) {
properties.load( in2 ); properties.load( reader );
} }
return properties; return properties;
} }

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -147,6 +148,25 @@ public interface FlatSystemProperties
*/ */
String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder"; String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder";
/**
* Species whether popup windows may be reused without (temporary) hiding them.
* E.g. if "moving" a tooltip to follow the mouse pointer, normally it is necessary
* to hide the tooltip and show it again at the new location, which causes some
* flicker with heavy-weight popup windows that FlatLaf uses on all platforms.
* <p>
* If {@code true}, hiding popup window is deferred for an event cycle,
* which allows reusing still visible popup window and avoids flicker when "moving" the popup.
* <p>
* Note that {@link JPopupMenu} popup windows (menus and combobox lists) are newer reused.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*
* @since 3.6.2
*/
String REUSE_VISIBLE_POPUP_WINDOW = "flatlaf.reuseVisiblePopupWindow";
/** /**
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens. * Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
* <p> * <p>

View File

@@ -25,12 +25,15 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer; import java.io.StreamTokenizer;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Executable; import java.lang.reflect.Executable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -112,6 +115,14 @@ class UIDefaultsLoader
Set<String> specialPrefixes = FlatLaf.getUIKeySpecialPrefixes(); Set<String> specialPrefixes = FlatLaf.getUIKeySpecialPrefixes();
return new Properties() { return new Properties() {
@Override
public void load( InputStream in ) throws IOException {
// use UTF-8 to load properties file
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 )) {
super.load( reader );
}
}
@Override @Override
public synchronized Object put( Object k, Object value ) { public synchronized Object put( Object k, Object value ) {
// process key prefixes (while loading properties files) // process key prefixes (while loading properties files)
@@ -198,16 +209,46 @@ class UIDefaultsLoader
if( classLoader == null ) if( classLoader == null )
classLoader = FlatLaf.class.getClassLoader(); classLoader = FlatLaf.class.getClassLoader();
boolean found = false;
for( Class<?> lafClass : lafClasses ) { for( Class<?> lafClass : lafClasses ) {
String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties"; String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties";
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) { try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
if( in != null ) if( in != null ) {
properties.load( in ); properties.load( in );
found = true;
}
}
}
// fallback for named Java modules
if( !found ) {
// Get package URL using ClassLoader.getResource(...) because this works
// also in named Java modules, even without opening the package in module-info.java.
// This extra step is necessary because ClassLoader.getResource("<package>/<file>.properties")
// does not work for named Java modules.
URL url = classLoader.getResource( packageName );
if( url == null )
continue;
String packageUrl = url.toExternalForm();
if( !packageUrl.endsWith( "/" ) )
packageUrl = packageUrl.concat( "/" );
for( Class<?> lafClass : lafClasses ) {
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );
try( InputStream in = propertiesUrl.openStream() ) {
properties.load( in );
} catch( FileNotFoundException ex ) {
// ignore
}
} }
} }
} else if( source instanceof URL ) { } else if( source instanceof URL ) {
// load from package URL // load from package URL
URL packageUrl = (URL) source; String packageUrl = ((URL)source).toExternalForm();
if( !packageUrl.endsWith( "/" ) )
packageUrl = packageUrl.concat( "/" );
for( Class<?> lafClass : lafClasses ) { for( Class<?> lafClass : lafClasses ) {
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" ); URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );

View File

@@ -302,6 +302,7 @@ public class FlatListUI
ListModel dataModel, ListSelectionModel selModel, int leadIndex ) ListModel dataModel, ListSelectionModel selModel, int leadIndex )
{ {
boolean isSelected = selModel.isSelectedIndex( row ); boolean isSelected = selModel.isSelectedIndex( row );
boolean isDropRow = isDropRow( row );
// paint alternating rows // paint alternating rows
if( alternateRowColor != null && row % 2 != 0 && if( alternateRowColor != null && row % 2 != 0 &&
@@ -335,7 +336,7 @@ public class FlatListUI
} }
// rounded selection or selection insets // rounded selection or selection insets
if( isSelected && if( (isSelected || isDropRow) &&
!isFileList && // rounded selection is not supported for file list !isFileList && // rounded selection is not supported for file list
(rendererComponent instanceof DefaultListCellRenderer || (rendererComponent instanceof DefaultListCellRenderer ||
rendererComponent instanceof BasicComboBoxRenderer) && rendererComponent instanceof BasicComboBoxRenderer) &&
@@ -376,7 +377,22 @@ public class FlatListUI
this.getColor() == rendererComponent.getBackground() ) this.getColor() == rendererComponent.getBackground() )
{ {
inPaintSelection = true; inPaintSelection = true;
paintCellSelection( this, row, x, y, width, height ); if( isDropRow ) {
// for rounded drop background, it is necessary to first
// paint selection background because may be not rounded on some corners
if( isSelected ) {
Color oldColor = getColor();
setColor( list.getSelectionBackground() );
paintCellSelection( this, row, x, y, width, height );
setColor( oldColor );
}
// paint drop background
float arc = UIScale.scale( selectionArc / 2f );
FlatUIUtils.paintSelection( this, x, y, width, height,
UIScale.scale( selectionInsets ), arc, arc, arc, arc, 0 );
} else
paintCellSelection( this, row, x, y, width, height );
inPaintSelection = false; inPaintSelection = false;
} else } else
super.fillRect( x, y, width, height ); super.fillRect( x, y, width, height );
@@ -475,4 +491,15 @@ public class FlatListUI
FlatListUI ui = (FlatListUI) list.getUI(); FlatListUI ui = (FlatListUI) list.getUI();
ui.paintCellSelection( g, row, x, y, width, height ); ui.paintCellSelection( g, row, x, y, width, height );
} }
/**
* Checks whether dropping on a row.
* See DefaultListCellRenderer.getListCellRendererComponent().
*/
private boolean isDropRow( int row ) {
JList.DropLocation dropLocation = list.getDropLocation();
return dropLocation != null &&
!dropLocation.isInsert() &&
dropLocation.getIndex() == row;
}
} }

View File

@@ -546,7 +546,15 @@ public class FlatPopupFactory
int x = popupWindow.getX(); int x = popupWindow.getX();
int y = popupWindow.getY(); int y = popupWindow.getY();
popup.show(); if( !popupWindow.isVisible() )
popup.show();
else {
// if the popup window is already visible (because it is reused),
// do not invoke Popup.show() because this would invoke Window.toFront(),
// which may have the side effect that an inactive owner window
// would be also moved to front and maybe hide previously active window
popupWindow.pack();
}
// restore popup window location if it has changed // restore popup window location if it has changed
// (probably scaled when screens use different scale factors) // (probably scaled when screens use different scale factors)
@@ -668,8 +676,11 @@ public class FlatPopupFactory
return; return;
disposed = true; disposed = true;
// immediately hide non-heavy weight popups or combobox popups // immediately hide non-heavy weight popups, popup menus and combobox popups
if( !(popupWindow instanceof JWindow) || contents instanceof BasicComboPopup ) { // of if system property is false
if( !(popupWindow instanceof JWindow) || contents instanceof JPopupMenu ||
!FlatSystemProperties.getBoolean( FlatSystemProperties.REUSE_VISIBLE_POPUP_WINDOW, true ) )
{
hideImpl(); hideImpl();
return; return;
} }

View File

@@ -20,6 +20,7 @@ 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.Dimension;
import java.awt.EventQueue;
import java.awt.Frame; import java.awt.Frame;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
@@ -153,8 +154,28 @@ public class FlatRootPaneUI
Container parent = c.getParent(); Container parent = c.getParent();
if( parent instanceof JFrame || parent instanceof JDialog ) { if( parent instanceof JFrame || parent instanceof JDialog ) {
Color background = parent.getBackground(); Color background = parent.getBackground();
if( background == null || background instanceof UIResource ) if( background == null || background instanceof UIResource ) {
parent.setBackground( UIManager.getColor( "control" ) ); if( SystemInfo.isMacOS ) {
// Setting window background on macOS immediately fills the whole window
// with that color, and slightly delayed, the Swing repaint manager
// repaints the actual window content. This results in some flashing
// when switching from a light to a dark theme (or vice versa).
// --> delay setting window background and immediately repaint window content
Runnable r = () -> {
parent.setBackground( UIManager.getColor( "control" ) );
c.paintImmediately( 0, 0, c.getWidth(), c.getHeight() );
};
// for class FlatAnimatedLafChange:
// if animated Laf change is in progress, set background color when
// animation has finished to avoid/reduce flashing
if( c.getClientProperty( "FlatLaf.internal.animatedLafChange" ) != null )
c.putClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished", r );
else
EventQueue.invokeLater( r );
} else
parent.setBackground( UIManager.getColor( "control" ) );
}
} }
macClearBackgroundForTranslucentWindow( c ); macClearBackgroundForTranslucentWindow( c );

View File

@@ -577,7 +577,6 @@ public class FlatTreeUI
boolean isEditing = (editingComponent != null && editingRow == row); boolean isEditing = (editingComponent != null && editingRow == row);
boolean isSelected = tree.isRowSelected( row ); boolean isSelected = tree.isRowSelected( row );
boolean isDropRow = isDropRow( row ); boolean isDropRow = isDropRow( row );
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection();
// paint alternating rows // paint alternating rows
if( alternateRowColor != null && row % 2 != 0 ) { if( alternateRowColor != null && row % 2 != 0 ) {
@@ -608,7 +607,7 @@ public class FlatTreeUI
if( isSelected && isWideSelection() ) { if( isSelected && isWideSelection() ) {
Color oldColor = g.getColor(); Color oldColor = g.getColor();
g.setColor( selectionInactiveBackground ); g.setColor( selectionInactiveBackground );
paintWideSelection( g, bounds, row ); paintWideSelection( g, bounds, row, false );
g.setColor( oldColor ); g.setColor( oldColor );
} }
return; return;
@@ -628,7 +627,7 @@ public class FlatTreeUI
// renderer background/foreground // renderer background/foreground
Color oldBackgroundSelectionColor = null; Color oldBackgroundSelectionColor = null;
if( isSelected && !hasFocus && !isDropRow ) { if( isSelected && !hasFocus ) {
// apply inactive selection background/foreground if tree is not focused // apply inactive selection background/foreground if tree is not focused
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground ); oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
setRendererForeground( rendererComponent, selectionInactiveForeground ); setRendererForeground( rendererComponent, selectionInactiveForeground );
@@ -655,26 +654,12 @@ public class FlatTreeUI
} }
// paint selection background // paint selection background
if( needsSelectionPainting ) { if( isSelected && isPaintSelection() ) {
// set selection color Color selectionColor = rendererComponent instanceof DefaultTreeCellRenderer
Color oldColor = g.getColor(); ? ((DefaultTreeCellRenderer)rendererComponent).getBackgroundSelectionColor()
g.setColor( isDropRow : (hasFocus ? selectionBackground : selectionInactiveBackground);
? UIManager.getColor( "Tree.dropCellBackground" )
: (rendererComponent instanceof DefaultTreeCellRenderer
? ((DefaultTreeCellRenderer)rendererComponent).getBackgroundSelectionColor()
: (hasFocus ? selectionBackground : selectionInactiveBackground)) );
if( isWideSelection() ) { paintRowSelection( g, selectionColor, rendererComponent, bounds, row, false );
// wide selection
paintWideSelection( g, bounds, row );
} else {
// non-wide selection
paintCellBackground( g, rendererComponent, bounds, row, true );
}
// this is actually not necessary because renderer should always set color
// before painting, but doing anyway to avoid any side effect (in bad renderers)
g.setColor( oldColor );
} else { } else {
// paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set // paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set
if( rendererComponent instanceof DefaultTreeCellRenderer ) { if( rendererComponent instanceof DefaultTreeCellRenderer ) {
@@ -683,12 +668,19 @@ public class FlatTreeUI
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) { if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
Color oldColor = g.getColor(); Color oldColor = g.getColor();
g.setColor( bg ); g.setColor( bg );
paintCellBackground( g, rendererComponent, bounds, row, false ); paintCellBackground( g, rendererComponent, bounds, row, false, false );
g.setColor( oldColor ); g.setColor( oldColor );
} }
} }
} }
// paint drop background
// (this needs to be an extra step for rounded selection)
if( isDropRow && isPaintSelection() ) {
paintRowSelection( g, UIManager.getColor( "Tree.dropCellBackground" ),
rendererComponent, bounds, row, true );
}
// paint renderer // paint renderer
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true ); rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
@@ -699,6 +691,26 @@ public class FlatTreeUI
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor ); ((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
} }
private void paintRowSelection( Graphics g, Color color, Component rendererComponent,
Rectangle bounds, int row, boolean paintDropSelection )
{
// set selection color
Color oldColor = g.getColor();
g.setColor( color );
if( isWideSelection() ) {
// wide selection
paintWideSelection( g, bounds, row, paintDropSelection );
} else {
// non-wide selection
paintCellBackground( g, rendererComponent, bounds, row, true, paintDropSelection );
}
// this is actually not necessary because renderer should always set color
// before painting, but doing anyway to avoid any side effect (in bad renderers)
g.setColor( oldColor );
}
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) { private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
Color oldColor = null; Color oldColor = null;
@@ -735,11 +747,11 @@ public class FlatTreeUI
return oldColor; return oldColor;
} }
private void paintWideSelection( Graphics g, Rectangle bounds, int row ) { private void paintWideSelection( Graphics g, Rectangle bounds, int row, boolean paintDropSelection ) {
float arcTop, arcBottom; float arcTop, arcBottom;
arcTop = arcBottom = UIScale.scale( selectionArc / 2f ); arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
if( useUnitedRoundedSelection() ) { if( useUnitedRoundedSelection() && !paintDropSelection ) {
if( row > 0 && tree.isRowSelected( row - 1 ) ) if( row > 0 && tree.isRowSelected( row - 1 ) )
arcTop = 0; arcTop = 0;
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) ) if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) )
@@ -751,7 +763,7 @@ public class FlatTreeUI
} }
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds, private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
int row, boolean paintSelection ) int row, boolean paintSelection, boolean paintDropSelection )
{ {
int xOffset = 0; int xOffset = 0;
int imageOffset = 0; int imageOffset = 0;
@@ -769,7 +781,7 @@ public class FlatTreeUI
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight; float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f ); arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
if( useUnitedRoundedSelection() ) { if( useUnitedRoundedSelection() && !paintDropSelection ) {
if( row > 0 && tree.isRowSelected( row - 1 ) ) { if( row > 0 && tree.isRowSelected( row - 1 ) ) {
Rectangle r = getPathBounds( tree, tree.getPathForRow( row - 1 ) ); Rectangle r = getPathBounds( tree, tree.getPathForRow( row - 1 ) );
arcTopLeft = Math.min( arcTopLeft, r.x - bounds.x ); arcTopLeft = Math.min( arcTopLeft, r.x - bounds.x );

View File

@@ -35,11 +35,11 @@ build script:
Otherwise, download `flatlaf-extras-<version>.jar` here: Otherwise, download `flatlaf-extras-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-extras?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-extras)
If SVG classes are used, `jsvg-<version>.jar` is also required: If SVG classes are used, `jsvg-<version>.jar` is also required:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg) [![Maven Central](https://img.shields.io/maven-central/v/com.github.weisj/jsvg?style=flat-square)](https://central.sonatype.com/artifact/com.github.weisj/jsvg)
Supported JSVG versions: Supported JSVG versions:

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLayeredPane; import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.Animator; import com.formdev.flatlaf.util.Animator;
@@ -52,15 +53,13 @@ public class FlatAnimatedLafChange
public static int duration = 160; public static int duration = 160;
/** /**
* The resolution of the animation in milliseconds. Default is 30 ms. * The resolution of the animation in milliseconds. Default is 16 ms.
*/ */
public static int resolution = 30; public static int resolution = 16;
private static Animator animator; private static Animator animator;
private static final Map<JLayeredPane, JComponent> oldUIsnapshots = new WeakHashMap<>(); private static final Map<JLayeredPane, SnapshotLayer> snapshots = new WeakHashMap<>();
private static final Map<JLayeredPane, JComponent> newUIsnapshots = new WeakHashMap<>();
private static float alpha; private static float alpha;
private static boolean inShowSnapshot;
/** /**
* Create a snapshot of the old UI and shows it on top of the UI. * Create a snapshot of the old UI and shows it on top of the UI.
@@ -77,59 +76,52 @@ public class FlatAnimatedLafChange
alpha = 1; alpha = 1;
// show snapshot of old UI // show snapshot of old UI
showSnapshot( true, oldUIsnapshots ); showSnapshot( true );
} }
private static void showSnapshot( boolean useAlpha, Map<JLayeredPane, JComponent> map ) { private static void showSnapshot( boolean old ) {
inShowSnapshot = true;
// create snapshots for all shown windows // create snapshots for all shown windows
Window[] windows = Window.getWindows(); Window[] windows = Window.getWindows();
for( Window window : windows ) { for( Window window : windows ) {
if( !(window instanceof RootPaneContainer) || !window.isShowing() ) if( !(window instanceof RootPaneContainer) || !window.isShowing() )
continue; continue;
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
// create snapshot image // create snapshot image
// (using volatile image to have correct sub-pixel text rendering on Java 9+) // (using volatile image to have correct sub-pixel text rendering on Java 9+)
VolatileImage snapshot = window.createVolatileImage( window.getWidth(), window.getHeight() ); VolatileImage snapshotImage = layeredPane.createVolatileImage( layeredPane.getWidth(), layeredPane.getHeight() );
if( snapshot == null ) if( snapshotImage == null )
continue; continue;
// paint window to snapshot image // paint window to snapshot image
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane(); layeredPane.paint( snapshotImage.getGraphics() );
layeredPane.paint( snapshot.getGraphics() );
// create snapshot layer, which is added to layered pane and paints if( old ) {
// snapshot with animated alpha // create snapshot layer, which is added to layered pane and paints
JComponent snapshotLayer = new JComponent() { // snapshot with animated alpha
@Override SnapshotLayer snapshotLayer = new SnapshotLayer();
public void paint( Graphics g ) {
if( inShowSnapshot || snapshot.contentsLost() )
return;
if( useAlpha )
((Graphics2D)g).setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) );
g.drawImage( snapshot, 0, 0, null );
}
@Override
public void removeNotify() {
super.removeNotify();
// release system resources used by volatile image
snapshot.flush();
}
};
if( !useAlpha )
snapshotLayer.setOpaque( true ); snapshotLayer.setOpaque( true );
snapshotLayer.setSize( layeredPane.getSize() ); snapshotLayer.setSize( layeredPane.getSize() );
snapshotLayer.oldSnapshotImage = snapshotImage;
// add image layer to layered pane snapshots.put( layeredPane, snapshotLayer );
layeredPane.add( snapshotLayer, Integer.valueOf( JLayeredPane.DRAG_LAYER + (useAlpha ? 2 : 1) ) ); } else {
map.put( layeredPane, snapshotLayer ); SnapshotLayer snapshotLayer = snapshots.get( layeredPane );
if( snapshotLayer == null ) {
snapshotImage.flush();
continue;
}
snapshotLayer.newSnapshotImage = snapshotImage;
// add snapshot layer to layered pane
layeredPane.add( snapshotLayer, Integer.valueOf( JLayeredPane.DRAG_LAYER + 1 ) );
// let FlatRootPaneUI know that animated Laf change is in progress
layeredPane.getRootPane().putClientProperty( "FlatLaf.internal.animatedLafChange", true );
}
} }
inShowSnapshot = false;
} }
/** /**
@@ -141,23 +133,22 @@ public class FlatAnimatedLafChange
if( !FlatSystemProperties.getBoolean( "flatlaf.animatedLafChange", true ) ) if( !FlatSystemProperties.getBoolean( "flatlaf.animatedLafChange", true ) )
return; return;
if( oldUIsnapshots.isEmpty() ) if( snapshots.isEmpty() )
return; return;
// show snapshot of new UI // show snapshot of new UI
showSnapshot( false, newUIsnapshots ); showSnapshot( false );
// create animator // create animator
animator = new Animator( duration, fraction -> { animator = new Animator( duration, fraction -> {
if( fraction < 0.1 || fraction > 0.9 )
return; // ignore initial and last events
alpha = 1f - fraction; alpha = 1f - fraction;
// repaint snapshots // repaint snapshots
for( Map.Entry<JLayeredPane, JComponent> e : oldUIsnapshots.entrySet() ) { for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
if( e.getKey().isShowing() ) if( e.getKey().isShowing() ) {
e.getValue().repaint(); SnapshotLayer snapshotLayer = e.getValue();
snapshotLayer.paintImmediately( 0, 0, snapshotLayer.getWidth(),snapshotLayer.getHeight() );
}
} }
Toolkit.getDefaultToolkit().sync(); Toolkit.getDefaultToolkit().sync();
@@ -171,18 +162,27 @@ public class FlatAnimatedLafChange
} }
private static void hideSnapshot() { private static void hideSnapshot() {
hideSnapshot( oldUIsnapshots );
hideSnapshot( newUIsnapshots );
}
private static void hideSnapshot( Map<JLayeredPane, JComponent> map ) {
// remove snapshots // remove snapshots
for( Map.Entry<JLayeredPane, JComponent> e : map.entrySet() ) { for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
e.getKey().remove( e.getValue() ); JLayeredPane layeredPane = e.getKey();
e.getKey().repaint(); SnapshotLayer snapshotLayer = e.getValue();
layeredPane.remove( snapshotLayer );
layeredPane.repaint();
snapshotLayer.flushSnapshotImages();
// run Runnable that FlatRootPaneUI put into client properties
JRootPane rootPane = layeredPane.getRootPane();
rootPane.putClientProperty( "FlatLaf.internal.animatedLafChange", null );
Runnable r = (Runnable) rootPane.getClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished" );
if( r != null ) {
rootPane.putClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished", null );
r.run();
}
} }
map.clear(); snapshots.clear();
} }
/** /**
@@ -194,4 +194,40 @@ public class FlatAnimatedLafChange
else else
hideSnapshot(); hideSnapshot();
} }
//---- class SnapshotLayer ------------------------------------------------
private static class SnapshotLayer
extends JComponent
{
VolatileImage oldSnapshotImage;
VolatileImage newSnapshotImage;
@Override
public void paint( Graphics g ) {
if( oldSnapshotImage.contentsLost() ||
newSnapshotImage == null || newSnapshotImage.contentsLost() )
return;
// draw new UI snapshot
g.drawImage( newSnapshotImage, 0, 0, null );
// draw old UI snapshot
((Graphics2D)g).setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) );
g.drawImage( oldSnapshotImage, 0, 0, null );
}
@Override
public void removeNotify() {
super.removeNotify();
flushSnapshotImages();
}
void flushSnapshotImages() {
// release system resources used by volatile image
oldSnapshotImage.flush();
if( newSnapshotImage != null )
newSnapshotImage.flush();
}
}
} }

View File

@@ -102,4 +102,4 @@ build script:
Otherwise, download `flatlaf-fonts-inter-<version>.jar` here: Otherwise, download `flatlaf-fonts-inter-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-inter/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-inter) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-fonts-inter?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-fonts-inter)

View File

@@ -83,4 +83,4 @@ build script:
Otherwise, download `flatlaf-fonts-jetbrains-mono-<version>.jar` here: Otherwise, download `flatlaf-fonts-jetbrains-mono-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-jetbrains-mono/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-jetbrains-mono) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-fonts-jetbrains-mono?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-fonts-jetbrains-mono)

View File

@@ -83,4 +83,4 @@ build script:
Otherwise, download `flatlaf-fonts-roboto-mono-<version>.jar` here: Otherwise, download `flatlaf-fonts-roboto-mono-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-roboto-mono/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-roboto-mono) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-fonts-roboto-mono?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-fonts-roboto-mono)

View File

@@ -99,4 +99,4 @@ build script:
Otherwise, download `flatlaf-fonts-roboto-<version>.jar` here: Otherwise, download `flatlaf-fonts-roboto-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-roboto/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-fonts-roboto) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-fonts-roboto?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-fonts-roboto)

View File

@@ -22,7 +22,7 @@ build script:
Otherwise, download `flatlaf-intellij-themes-<version>.jar` here: Otherwise, download `flatlaf-intellij-themes-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-intellij-themes/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-intellij-themes) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-intellij-themes?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-intellij-themes)
How to use? How to use?

View File

@@ -37,10 +37,10 @@ build script:
Otherwise, download `flatlaf-jide-oss-<version>.jar` here: Otherwise, download `flatlaf-jide-oss-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-jide-oss/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-jide-oss) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-jide-oss?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-jide-oss)
JIDE Common Layer library `jide-oss-<version>.jar` (or JIDE Common Layer library `jide-oss-<version>.jar` (or
`jide-common-<version>.jar`) is also required: `jide-common-<version>.jar`) is also required:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/jide-oss/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/jide-oss) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/jide-oss?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/jide-oss)

View File

@@ -38,9 +38,9 @@ build script:
Otherwise, download `flatlaf-swingx-<version>.jar` here: Otherwise, download `flatlaf-swingx-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-swingx/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-swingx) [![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf-swingx?style=flat-square)](https://central.sonatype.com/artifact/com.formdev/flatlaf-swingx)
SwingX library `swingx-all-<version>.jar` is also required: SwingX library `swingx-all-<version>.jar` is also required:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.swinglabs.swingx/swingx-all/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/org.swinglabs.swingx/swingx-all) [![Maven Central](https://img.shields.io/maven-central/v/org.swinglabs.swingx/swingx-all?style=flat-square)](https://central.sonatype.com/artifact/org.swinglabs.swingx/swingx-all)

View File

@@ -7,6 +7,8 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/> <listEntry value="4"/>
</listAttribute> </listAttribute>
<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;sourceLookupDirector&gt;&#13;&#10; &lt;sourceContainers duplicates=&quot;false&quot;&gt;&#13;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;flatlaf-core&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;flatlaf-testing-modular-app&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10; &lt;/sourceContainers&gt;&#13;&#10;&lt;/sourceLookupDirector&gt;&#13;&#10;"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/> <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/> <booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/> <booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/>
@@ -17,11 +19,11 @@
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="-Ddummy=dummy"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="-Ddummy=dummy"/>
<listAttribute key="org.eclipse.jdt.launching.MODULEPATH"> <listAttribute key="org.eclipse.jdt.launching.MODULEPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-17/&quot; path=&quot;4&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-17/&quot; path=&quot;4&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/build/libs/flatlaf-testing-modular-app-3.0-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/run/flatlaf-testing-modular-app-999-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-core/build/libs/flatlaf-3.0-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/run/flatlaf-999-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-extras/build/libs/flatlaf-extras-3.0-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/run/flatlaf-extras-999-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-fonts-inter/build/libs/flatlaf-fonts-inter-3.19-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/run/flatlaf-fonts-inter-999-SNAPSHOT.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;C:/Users/charly/.gradle/caches/modules-2/files-2.1/com.formdev/svgSalamander/1.1.4/e61742cb8baaf9ecf57a9779763d1de21ca9db5a/svgSalamander-1.1.4.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/flatlaf-testing-modular-app/run/jsvg-999.jar&quot; path=&quot;4&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
</listAttribute> </listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="flatlaf-testing-modular-app"/> <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="flatlaf-testing-modular-app"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-m com.formdev.flatlaf.testing.modular.app/com.formdev.flatlaf.testing.modular.app.FlatModularAppTest"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-m com.formdev.flatlaf.testing.modular.app/com.formdev.flatlaf.testing.modular.app.FlatModularAppTest"/>

View File

@@ -30,3 +30,20 @@ flatlafModuleInfo {
dependsOn( ":flatlaf-extras:jar" ) dependsOn( ":flatlaf-extras:jar" )
dependsOn( ":flatlaf-fonts-inter:jar" ) dependsOn( ":flatlaf-fonts-inter:jar" )
} }
tasks {
register( "build-for-debugging" ) {
group = "build"
dependsOn( "build" )
doLast {
copy {
from( project.tasks["jar"].outputs )
from( configurations.runtimeClasspath )
into( "run" )
rename( "-[0-9][0-9.]*[0-9]", "-999" )
}
}
}
}

View File

@@ -38,8 +38,12 @@ public class FlatModularAppTest
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
FlatInterFont.installBasic(); FlatInterFont.installBasic();
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.testing.modular.app.themes" );
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.testing.modular.app.themes2",
FlatModularAppTest.class.getClassLoader() );
FlatLaf.registerCustomDefaultsSource( FlatLaf.registerCustomDefaultsSource(
FlatModularAppTest.class.getResource( "/com/formdev/flatlaf/testing/modular/app/themes/" ) ); FlatModularAppTest.class.getResource( "/com/formdev/flatlaf/testing/modular/app/themes3" ) );
FlatLightLaf.setup(); FlatLightLaf.setup();
JButton button1 = new JButton( "Hello" ); JButton button1 = new JButton( "Hello" );

View File

@@ -14,7 +14,4 @@
# limitations under the License. # limitations under the License.
# #
@background = #fff
@foreground = #f00 @foreground = #f00
ButtonUI = com.formdev.flatlaf.testing.modular.app.plaf.MyButtonUI

View File

@@ -0,0 +1,17 @@
#
# Copyright 2025 FormDev Software GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
@background = #efe

View File

@@ -0,0 +1,17 @@
#
# Copyright 2025 FormDev Software GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
ButtonUI = com.formdev.flatlaf.testing.modular.app.plaf.MyButtonUI

View File

@@ -162,6 +162,11 @@ public class FlatComponents2Test
for( JTree tree : allTrees ) for( JTree tree : allTrees )
expandTree( tree ); expandTree( tree );
// drop mode
dropModeComboBox.init( DropMode.class, false );
dropModeComboBox.setSelectedItem( DropMode.ON_OR_INSERT );
dropModeChanged();
} }
private void initTableEditors( JTable table ) { private void initTableEditors( JTable table ) {
@@ -311,13 +316,6 @@ public class FlatComponents2Test
xTable1.setDragEnabled( dnd ); xTable1.setDragEnabled( dnd );
xTreeTable1.setDragEnabled( dnd ); xTreeTable1.setDragEnabled( dnd );
DropMode dropMode = dnd ? DropMode.ON_OR_INSERT : DropMode.USE_SELECTION;
list1.setDropMode( dropMode );
tree1.setDropMode( dropMode );
table1.setDropMode( dropMode );
xTable1.setDropMode( dropMode );
xTreeTable1.setDropMode( dropMode );
String key = "FlatLaf.oldTransferHandler"; String key = "FlatLaf.oldTransferHandler";
if( dnd ) { if( dnd ) {
list1.putClientProperty( key, list1.getTransferHandler() ); list1.putClientProperty( key, list1.getTransferHandler() );
@@ -341,6 +339,32 @@ public class FlatComponents2Test
} }
} }
private void dropModeChanged() {
DropMode dropMode = dropModeComboBox.getSelectedValue();
DropMode dropMode2;
switch( dropMode ) {
case INSERT_ROWS:
case INSERT_COLS:
dropMode2 = DropMode.INSERT;
break;
case ON_OR_INSERT_ROWS:
case ON_OR_INSERT_COLS:
dropMode2 = DropMode.ON_OR_INSERT;
break;
default:
dropMode2 = dropMode;
break;
}
list1.setDropMode( dropMode2 );
tree1.setDropMode( dropMode2 );
table1.setDropMode( dropMode );
xTable1.setDropMode( dropMode );
xTreeTable1.setDropMode( dropMode );
}
private void tableHeaderButtonChanged() { private void tableHeaderButtonChanged() {
tableHeaderButtonChanged( table1ScrollPane ); tableHeaderButtonChanged( table1ScrollPane );
tableHeaderButtonChanged( xTable1ScrollPane ); tableHeaderButtonChanged( xTable1ScrollPane );
@@ -618,6 +642,7 @@ public class FlatComponents2Test
super.updateUI(); super.updateUI();
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
dropModeChanged();
showHorizontalLinesChanged(); showHorizontalLinesChanged();
showVerticalLinesChanged(); showVerticalLinesChanged();
intercellSpacingChanged(); intercellSpacingChanged();
@@ -673,6 +698,7 @@ public class FlatComponents2Test
leftSelectionInsetsCheckBox = new JCheckBox(); leftSelectionInsetsCheckBox = new JCheckBox();
rightSelectionInsetsCheckBox = new JCheckBox(); rightSelectionInsetsCheckBox = new JCheckBox();
dndCheckBox = new JCheckBox(); dndCheckBox = new JCheckBox();
dropModeComboBox = new FlatTestEnumComboBox<>();
listOptionsPanel = new JPanel(); listOptionsPanel = new JPanel();
JLabel listRendererLabel = new JLabel(); JLabel listRendererLabel = new JLabel();
listRendererComboBox = new JComboBox<>(); listRendererComboBox = new JComboBox<>();
@@ -963,6 +989,7 @@ public class FlatComponents2Test
"[]0" + "[]0" +
"[]0" + "[]0" +
"[]rel" + "[]rel" +
"[]" +
"[]")); "[]"));
//---- roundedSelectionCheckBox ---- //---- roundedSelectionCheckBox ----
@@ -1004,6 +1031,10 @@ public class FlatComponents2Test
dndCheckBox.setMnemonic('D'); dndCheckBox.setMnemonic('D');
dndCheckBox.addActionListener(e -> dndChanged()); dndCheckBox.addActionListener(e -> dndChanged());
generalOptionsPanel.add(dndCheckBox, "cell 0 4"); generalOptionsPanel.add(dndCheckBox, "cell 0 4");
//---- dropModeComboBox ----
dropModeComboBox.addActionListener(e -> dropModeChanged());
generalOptionsPanel.add(dropModeComboBox, "cell 0 5");
} }
add(generalOptionsPanel, "cell 0 4 4 1"); add(generalOptionsPanel, "cell 0 4 4 1");
@@ -1272,6 +1303,7 @@ public class FlatComponents2Test
private JCheckBox leftSelectionInsetsCheckBox; private JCheckBox leftSelectionInsetsCheckBox;
private JCheckBox rightSelectionInsetsCheckBox; private JCheckBox rightSelectionInsetsCheckBox;
private JCheckBox dndCheckBox; private JCheckBox dndCheckBox;
private FlatTestEnumComboBox<DropMode> dropModeComboBox;
private JPanel listOptionsPanel; private JPanel listOptionsPanel;
private JComboBox<String> listRendererComboBox; private JComboBox<String> listRendererComboBox;
private JComboBox<String> listLayoutOrientationField; private JComboBox<String> listLayoutOrientationField;

View File

@@ -299,7 +299,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 8,hidemode 3" "$layoutConstraints": "insets 8,hidemode 3"
"$columnConstraints": "[left]" "$columnConstraints": "[left]"
"$rowConstraints": "[][]0[]0[]rel[]" "$rowConstraints": "[][]0[]0[]rel[][]"
} ) { } ) {
name: "generalOptionsPanel" name: "generalOptionsPanel"
"border": new javax.swing.border.TitledBorder( "General Control" ) "border": new javax.swing.border.TitledBorder( "General Control" )
@@ -379,6 +379,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4" "value": "cell 0 4"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.testing.FlatTestEnumComboBox" ) {
name: "dropModeComboBox"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.typeParameters": "DropMode"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dropModeChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4 4 1" "value": "cell 0 4 4 1"
} ) } )

View File

@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringReader; import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@@ -177,7 +178,7 @@ class FlatCompletionProvider
try { try {
try( InputStream in = getClass().getResourceAsStream( "/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt" ) ) { try( InputStream in = getClass().getResourceAsStream( "/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt" ) ) {
if( in != null ) { if( in != null ) {
try( BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ) ) ) { try( BufferedReader reader = new BufferedReader( new InputStreamReader( in, StandardCharsets.UTF_8 ) ) ) {
String key; String key;
while( (key = reader.readLine()) != null ) { while( (key = reader.readLine()) != null ) {
if( !isIgnored( key ) ) if( !isIgnored( key ) )

View File

@@ -23,6 +23,7 @@ import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.InputMap; import javax.swing.InputMap;
@@ -211,7 +212,7 @@ class FlatThemeEditorPane
void load( File file ) throws IOException { void load( File file ) throws IOException {
this.file = file; this.file = file;
textArea.load( FileLocation.create( file ), "UTF-8" ); textArea.load( FileLocation.create( file ), StandardCharsets.UTF_8 );
} }
boolean reloadIfNecessary() { boolean reloadIfNecessary() {

View File

@@ -39,6 +39,7 @@ import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.time.Year; import java.time.Year;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -675,7 +676,7 @@ class FlatThemeFileEditor
{ {
try( try(
FileOutputStream out = new FileOutputStream( file ); FileOutputStream out = new FileOutputStream( file );
Writer writer = new OutputStreamWriter( out, "UTF-8" ); Writer writer = new OutputStreamWriter( out, StandardCharsets.UTF_8 );
) { ) {
writer.write( content ); writer.write( content );
} }

View File

@@ -19,6 +19,9 @@ package com.formdev.flatlaf.themeeditor;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -109,8 +112,11 @@ class FlatThemePropertiesBaseManager
String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties"; String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) { try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
Properties properties = new Properties(); Properties properties = new Properties();
if( in != null ) if( in != null ) {
properties.load( in ); try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 )) {
properties.load( in );
}
}
coreThemes.put( lafClass.getSimpleName(), properties ); coreThemes.put( lafClass.getSimpleName(), properties );
} catch( IOException ex ) { } catch( IOException ex ) {
ex.printStackTrace(); ex.printStackTrace();

View File

@@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
# #
flatlaf.releaseVersion = 3.6.1 flatlaf.releaseVersion = 3.6.2
flatlaf.developmentVersion = 3.7-SNAPSHOT flatlaf.developmentVersion = 3.7-SNAPSHOT
org.gradle.parallel = true org.gradle.parallel = true