Compare commits

...

8 Commits

9 changed files with 168 additions and 106 deletions

View File

@@ -72,14 +72,36 @@ jobs:
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied # tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
run: ./gradlew build-natives --no-daemon run: ./gradlew build-natives --no-daemon
- name: Sign Windows DLLs - name: Upload unsigned Windows DLLs for signing by SignPath.org
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
uses: skymatic/code-sign-action@v3 id: windows-unsigned
uses: actions/upload-artifact@v4
with: with:
certificate: '${{ secrets.CODE_SIGN_CERT_BASE64 }}' name: FlatLaf-natives-windows-unsigned
password: '${{ secrets.CODE_SIGN_CERT_PASSWORD }}' path: flatlaf-natives/flatlaf-natives-windows/build/lib/main/release/**/*.dll
certificatesha1: '${{ secrets.CODE_SIGN_CERT_SHA1 }}'
folder: 'flatlaf-core/src/main/resources/com/formdev/flatlaf/natives' - name: Sign Windows DLLs using SignPath.org
if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }}
project-slug: FlatLaf
signing-policy-slug: release-signing
artifact-configuration-slug: windows-dlls
github-artifact-id: ${{ steps.windows-unsigned.outputs.artifact-id }}
wait-for-completion: true
output-artifact-directory: flatlaf-natives/flatlaf-natives-windows/build/lib/signed
- name: Copy signed Windows DLLs to flatlaf-core
if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
shell: bash
run: |
SRC=flatlaf-natives/flatlaf-natives-windows/build/lib/signed
DEST=flatlaf-core/src/main/resources/com/formdev/flatlaf/natives
cp $SRC/aarch64/flatlaf-natives-windows.dll $DEST/flatlaf-windows-arm64.dll
cp $SRC/x86/flatlaf-natives-windows.dll $DEST/flatlaf-windows-x86.dll
cp $SRC/x86-64/flatlaf-natives-windows.dll $DEST/flatlaf-windows-x86_64.dll
- name: Sign macOS natives - name: Sign macOS natives
if: matrix.os == 'DISABLED--macos-latest' if: matrix.os == 'DISABLED--macos-latest'
@@ -112,7 +134,7 @@ jobs:
# cleanup # cleanup
security delete-keychain $KEYCHAIN_PATH security delete-keychain $KEYCHAIN_PATH
- name: Set artifacts pattern - name: Set artifacts pattern for upload step
shell: bash shell: bash
run: | run: |
case ${{ matrix.os }} in case ${{ matrix.os }} in

View File

@@ -7,6 +7,15 @@ FlatLaf Change Log
#1068) #1068)
- Popup: Fixed scrolling popup painting issue on Windows 10 when a glass pane is - Popup: Fixed scrolling popup painting issue on Windows 10 when a glass pane is
visible and frame is maximized. (issue #1071) visible and frame is maximized. (issue #1071)
- Slider: Styling `thumbSize` or `focusWidth` did not update slider size/layout.
(PR #1074)
- ToolBar: Grip disappeared when switching between Look and Feels. (issue #1075)
- Extras:
- UI defaults inspector: Fixed NPE if color of `FlatLineBorder` is null. Also
use `FlatLineBorder` line color as cell background color in "Value" column.
(PR #1080)
- `FlatDesktop`: Avoid unnecessary logging if desktop is not supported (e.g.
on NixOS with Plasma/KDE desktop).
## 3.7 ## 3.7

View File

@@ -76,10 +76,19 @@ Otherwise, download `flatlaf-<version>.jar` here:
[![Maven Central](https://img.shields.io/maven-central/v/com.formdev/flatlaf?style=flat-square)](https://central.sonatype.com/artifact/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
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/) [Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
for instructions on how to redistribute FlatLaf native libraries with your for instructions on how to redistribute FlatLaf native libraries with your
application. application.
- Windows DLLs: Free code signing provided by
[SignPath.io](https://about.signpath.io/), certificate by
[SignPath Foundation](https://signpath.org/).
- If repackaging FlatLaf (and other) JARs into a single fat/uber JAR:
- add `Multi-Release: true` to `META-INF/MANIFEST.MF`
- keep `META-INF/versions/` and `META-INF/services/` directories
- merge content of equally named files in `META-INF/services/`
- If using obfuscation/minimizing/shrinking tools (e.g. **ProGuard** or
**Shadow**), exclude package `com.formdev.flatlaf` and all sub-packages.
### Snapshots ### Snapshots

View File

@@ -227,7 +227,13 @@ public class FlatSliderUI
/** @since 2 */ /** @since 2 */
protected void applyStyle( Object style ) { protected void applyStyle( Object style ) {
Dimension oldThumbSize = thumbSize;
int oldFocusWidth = focusWidth;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
if( !thumbSize.equals( oldThumbSize ) || focusWidth != oldFocusWidth )
calculateGeometry();
} }
/** @since 2 */ /** @since 2 */

View File

@@ -34,7 +34,6 @@ import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map; import java.util.Map;
import javax.swing.Action; import javax.swing.Action;
@@ -66,6 +65,7 @@ import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatCheckBoxIcon; import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatUIUtils.FlatPropertyWatcher;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
@@ -189,29 +189,26 @@ public class FlatTableUI
if( rowHeight > 0 ) if( rowHeight > 0 )
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) ); LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table ); if( !showHorizontalLines ) {
if( watcher != null ) FlatPropertyWatcher.runIfNotChanged( table, "showHorizontalLines", () -> {
watcher.enabled = false; oldShowHorizontalLines = table.getShowHorizontalLines();
table.setShowHorizontalLines( false );
if( !showHorizontalLines && (watcher == null || !watcher.showHorizontalLinesChanged) ) { } );
oldShowHorizontalLines = table.getShowHorizontalLines();
table.setShowHorizontalLines( false );
} }
if( !showVerticalLines && (watcher == null || !watcher.showVerticalLinesChanged) ) { if( !showVerticalLines ) {
oldShowVerticalLines = table.getShowVerticalLines(); FlatPropertyWatcher.runIfNotChanged( table, "showVerticalLines", () -> {
table.setShowVerticalLines( false ); oldShowVerticalLines = table.getShowVerticalLines();
table.setShowVerticalLines( false );
} );
} }
if( intercellSpacing != null && (watcher == null || !watcher.intercellSpacingChanged) ) { if( intercellSpacing != null ) {
oldIntercellSpacing = table.getIntercellSpacing(); FlatPropertyWatcher.runIfNotChanged( table, "rowMargin", () -> {
table.setIntercellSpacing( intercellSpacing ); oldIntercellSpacing = table.getIntercellSpacing();
table.setIntercellSpacing( intercellSpacing );
} );
} }
if( watcher != null )
watcher.enabled = true;
else
table.addPropertyChangeListener( new FlatTablePropertyWatcher() );
// install boolean renderer // install boolean renderer
oldBooleanRenderer = table.getDefaultRenderer( Boolean.class ); oldBooleanRenderer = table.getDefaultRenderer( Boolean.class );
if( oldBooleanRenderer instanceof UIResource ) if( oldBooleanRenderer instanceof UIResource )
@@ -231,25 +228,24 @@ public class FlatTableUI
oldStyleValues = null; oldStyleValues = null;
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
if( watcher != null )
watcher.enabled = false;
// restore old show horizontal/vertical lines (if not modified) // restore old show horizontal/vertical lines (if not modified)
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() && if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() ) {
(watcher == null || !watcher.showHorizontalLinesChanged) ) FlatPropertyWatcher.runIfNotChanged( table, "showHorizontalLines", () -> {
table.setShowHorizontalLines( true ); table.setShowHorizontalLines( true );
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() && } );
(watcher == null || !watcher.showVerticalLinesChanged) ) }
table.setShowVerticalLines( true ); if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() ) {
FlatPropertyWatcher.runIfNotChanged( table, "showVerticalLines", () -> {
table.setShowVerticalLines( true );
} );
}
// restore old intercell spacing (if not modified) // restore old intercell spacing (if not modified)
if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) && if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) ) {
(watcher == null || !watcher.intercellSpacingChanged) ) FlatPropertyWatcher.runIfNotChanged( table, "rowMargin", () -> {
table.setIntercellSpacing( oldIntercellSpacing ); table.setIntercellSpacing( oldIntercellSpacing );
} );
if( watcher != null ) }
watcher.enabled = true;
// uninstall boolean renderer // uninstall boolean renderer
if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) { if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) {
@@ -938,48 +934,6 @@ public class FlatTableUI
} }
} }
//---- class FlatTablePropertyWatcher -------------------------------------
/**
* Listener that watches for change of some table properties from application code.
* This information is used in {@link FlatTableUI#installDefaults()} and
* {@link FlatTableUI#uninstallDefaults()} to decide whether FlatLaf modifies those properties.
* If they are modified in application code, FlatLaf no longer changes them.
*
* The listener is added once for each table, but never removed.
* So switching Laf/theme reuses existing listener.
*/
private static class FlatTablePropertyWatcher
implements PropertyChangeListener
{
boolean enabled = true;
boolean showHorizontalLinesChanged;
boolean showVerticalLinesChanged;
boolean intercellSpacingChanged;
static FlatTablePropertyWatcher get( JTable table ) {
for( PropertyChangeListener l : table.getPropertyChangeListeners() ) {
if( l instanceof FlatTablePropertyWatcher )
return (FlatTablePropertyWatcher) l;
}
return null;
}
//---- interface PropertyChangeListener ----
@Override
public void propertyChange( PropertyChangeEvent e ) {
if( !enabled )
return;
switch( e.getPropertyName() ) {
case "showHorizontalLines": showHorizontalLinesChanged = true; break;
case "showVerticalLines": showVerticalLinesChanged = true; break;
case "rowMargin": intercellSpacingChanged = true; break;
}
}
}
//---- class FlatBooleanRenderer ------------------------------------------ //---- class FlatBooleanRenderer ------------------------------------------
private static class FlatBooleanRenderer private static class FlatBooleanRenderer

View File

@@ -47,6 +47,7 @@ import javax.swing.plaf.basic.BasicToolBarUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatUIUtils.FlatPropertyWatcher;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -144,11 +145,13 @@ public class FlatToolBarUI
hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" ); hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" );
// floatable // floatable
oldFloatable = null;
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) { if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
oldFloatable = toolBar.isFloatable(); FlatPropertyWatcher.runIfNotChanged( toolBar, "floatable", () -> {
toolBar.setFloatable( false ); oldFloatable = toolBar.isFloatable();
} else toolBar.setFloatable( false );
oldFloatable = null; } );
}
} }
@Override @Override
@@ -158,7 +161,9 @@ public class FlatToolBarUI
hoverButtonGroupBackground = null; hoverButtonGroupBackground = null;
if( oldFloatable != null ) { if( oldFloatable != null ) {
toolBar.setFloatable( oldFloatable ); FlatPropertyWatcher.runIfNotChanged( toolBar, "floatable", () -> {
toolBar.setFloatable( oldFloatable );
} );
oldFloatable = null; oldFloatable = null;
} }
} }

View File

@@ -44,6 +44,8 @@ import java.awt.geom.Path2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.function.Predicate; import java.util.function.Predicate;
@@ -1413,4 +1415,47 @@ debug*/
return delegate.isBorderOpaque(); return delegate.isBorderOpaque();
} }
} }
//---- class FlatPropertyWatcher ------------------------------------------
/**
* Listener that watches for change of a property from application code.
* This information can be used to decide whether FlatLaf modifies the property.
* If it is modified in application code, FlatLaf no longer changes it.
* <p>
* The listener is added once for a property, but never removed.
* So switching Laf/theme reuses existing listener.
*/
static class FlatPropertyWatcher
implements PropertyChangeListener
{
private boolean changed;
static void runIfNotChanged( JComponent c, String propName, Runnable runnable ) {
FlatPropertyWatcher watcher = getOrInstall( c, propName );
if( watcher.changed )
return;
runnable.run();
watcher.changed = false;
}
private static FlatPropertyWatcher getOrInstall( JComponent c, String propName ) {
for( PropertyChangeListener l : c.getPropertyChangeListeners( propName ) ) {
if( l instanceof FlatPropertyWatcher )
return (FlatPropertyWatcher) l;
}
FlatPropertyWatcher watcher = new FlatPropertyWatcher();
c.addPropertyChangeListener( propName, watcher );
return watcher;
}
//---- interface PropertyChangeListener ----
@Override
public void propertyChange( PropertyChangeEvent e ) {
changed = true;
}
}
} }

View File

@@ -43,7 +43,8 @@ public class FlatDesktop
public static boolean isSupported( Action action ) { public static boolean isSupported( Action action ) {
if( SystemInfo.isJava_9_orLater ) { if( SystemInfo.isJava_9_orLater ) {
try { try {
return Desktop.getDesktop().isSupported( Enum.valueOf( Desktop.Action.class, action.name() ) ); return Desktop.isDesktopSupported() &&
Desktop.getDesktop().isSupported( Enum.valueOf( Desktop.Action.class, action.name() ) );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
return false; return false;

View File

@@ -777,6 +777,9 @@ public class FlatUIDefaultsInspector
@SuppressWarnings( "FormatString" ) // Error Prone @SuppressWarnings( "FormatString" ) // Error Prone
private static String color2hex( Color color ) { private static String color2hex( Color color ) {
if( color == null )
return "";
int rgb = color.getRGB(); int rgb = color.getRGB();
boolean hasAlpha = color.getAlpha() != 255; boolean hasAlpha = color.getAlpha() != 255;
@@ -1018,28 +1021,36 @@ public class FlatUIDefaultsInspector
item = (Item) value; item = (Item) value;
init( table, item.key, isSelected, row ); init( table, item.key, isSelected, row );
// reset background, foreground and icon // get color of value
if( !(item.value instanceof Color) ) { valueColor = null;
if( item.value instanceof Color )
valueColor = (item.info instanceof Color[]) ? ((Color[])item.info)[0] : (Color) item.value;
else if( item.value instanceof FlatLineBorder )
valueColor = ((FlatLineBorder)item.value).getLineColor();
// reset background and foreground
if( valueColor == null ) {
setBackground( null ); setBackground( null );
setForeground( null ); setForeground( null );
} }
if( !(item.value instanceof Icon) )
setIcon( null );
// value to string // value to string
value = item.getValueAsString(); value = item.getValueAsString();
super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column ); super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
if( item.value instanceof Color ) { // set foreground, if value has color
Color color = (item.info instanceof Color[]) ? ((Color[])item.info)[0] : (Color) item.value; if( valueColor != null ) {
boolean isDark = new HSLColor( color ).getLuminance() < 70 && color.getAlpha() >= 128; boolean isDark = new HSLColor( valueColor ).getLuminance() < 70 && valueColor.getAlpha() >= 128;
valueColor = color;
setForeground( isDark ? Color.white : Color.black ); setForeground( isDark ? Color.white : Color.black );
} else if( item.value instanceof Icon ) { }
// set icon
if( item.value instanceof Icon ) {
Icon icon = (Icon) item.value; Icon icon = (Icon) item.value;
setIcon( new SafeIcon( icon ) ); setIcon( new SafeIcon( icon ) );
} } else
setIcon( null );
// set tooltip // set tooltip
String toolTipText = (item.value instanceof Object[]) String toolTipText = (item.value instanceof Object[])
@@ -1056,7 +1067,7 @@ public class FlatUIDefaultsInspector
@Override @Override
protected void paintComponent( Graphics g ) { protected void paintComponent( Graphics g ) {
if( item.value instanceof Color ) { if( valueColor != null ) {
int width = getWidth(); int width = getWidth();
int height = getHeight(); int height = getHeight();
Color background = valueColor; Color background = valueColor;