From 0a181f640756ec5788a18c06a36fc6614e2fc1b5 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 7 May 2020 00:07:02 +0200 Subject: [PATCH] InternalFrame: added drop shadows (issue #94) also made borders of internal frames in dark themes darker --- .../flatlaf/ui/FlatDropShadowBorder.java | 159 ++++++++++++++++++ .../flatlaf/ui/FlatInternalFrameUI.java | 22 ++- .../formdev/flatlaf/FlatDarkLaf.properties | 4 +- .../uidefaults/FlatDarkLaf_1.8.0_202-mac.txt | 4 +- .../uidefaults/FlatDarkLaf_1.8.0_202.txt | 4 +- 5 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatDropShadowBorder.java diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatDropShadowBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatDropShadowBorder.java new file mode 100644 index 00000000..1390e144 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatDropShadowBorder.java @@ -0,0 +1,159 @@ +/* + * Copyright 2020 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Insets; +import java.awt.RadialGradientPaint; +import java.awt.image.BufferedImage; +import com.formdev.flatlaf.util.HiDPIUtils; +import com.formdev.flatlaf.util.UIScale; + +/** + * Paints a drop shadow border around the component. + * + * @author Karl Tauber + */ +public class FlatDropShadowBorder + extends FlatEmptyBorder +{ + private final Color shadowColor; + private final int shadowSize; + private final int cornerInset; + private final int shadowAlpha; + + private Image shadowImage; + private Color lastShadowColor; + private double lastSystemScaleFactor; + private float lastUserScaleFactor; + + public FlatDropShadowBorder() { + this( null ); + } + + public FlatDropShadowBorder( Color shadowColor ) { + this( shadowColor, 4, 4, 128 ); + } + + public FlatDropShadowBorder( Color shadowColor, int shadowSize, int cornerInset, int shadowAlpha ) { + super( new Insets( 0, 0, shadowSize, shadowSize ) ); + this.shadowColor = shadowColor; + this.shadowSize = shadowSize; + this.cornerInset = cornerInset; + this.shadowAlpha = shadowAlpha; + } + + @Override + public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { + HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl ); + } + + private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { + Color shadowColor = (this.shadowColor != null) ? this.shadowColor : g.getColor(); + int shadowSize = (int) Math.ceil( UIScale.scale( this.shadowSize ) * scaleFactor ); + int cornerInset = (int) Math.ceil( UIScale.scale( this.cornerInset ) * scaleFactor ); + + // create and cache shadow image + float userScaleFactor = UIScale.getUserScaleFactor(); + if( shadowImage == null || + !shadowColor.equals( lastShadowColor ) || + lastSystemScaleFactor != scaleFactor || + lastUserScaleFactor != userScaleFactor ) + { + shadowImage = createShadowImage( shadowColor, shadowSize, shadowAlpha, + (float) (scaleFactor * userScaleFactor) ); + lastShadowColor = shadowColor; + lastSystemScaleFactor = scaleFactor; + lastUserScaleFactor = userScaleFactor; + } + +/*debug + int m = shadowImage.getWidth( null ); + g.setColor( Color.lightGray ); + g.drawRect( x - m - 1, y - m - 1, m + 1, m + 1 ); + g.setColor( Color.white ); + g.fillRect( x - m, y - m, m, m ); + g.drawImage( shadowImage, x - m, y - m, null ); +debug*/ + + int x1c = x + cornerInset; + int y1c = y + cornerInset; + int x1cs = x1c + shadowSize; + int y1cs = y1c + shadowSize; + + int x2s = x + width; + int y2s = y + height; + int x2 = x2s - shadowSize; + int y2 = y2s - shadowSize; + + int wh = (shadowSize * 2) - 1; + int center = shadowSize - 1; + + // left-bottom edge + g.drawImage( shadowImage, x1c, y2, x1cs, y2s, + 0, center, shadowSize, wh, null ); + + // bottom shadow + g.drawImage( shadowImage, x1cs, y2, x2, y2s, + center, center, center + 1, wh, null ); + + // right-bottom edge + g.drawImage( shadowImage, x2, y2, x2s, y2s, + center, center, wh, wh, null ); + + // right shadow + g.drawImage( shadowImage, x2, y1cs, x2s, y2, + center, center, wh, center + 1, null ); + + // right-top edge + g.drawImage( shadowImage, x2, y1c, x2s, y1cs, + center, 0, wh, shadowSize, null ); + } + + private static BufferedImage createShadowImage( Color shadowColor, int shadowSize, + int shadowAlpha, float scaleFactor ) + { + int shadowRGB = shadowColor.getRGB() & 0xffffff; + Color startColor = new Color( shadowRGB | ((shadowAlpha & 0xff) << 24), true ); + Color midColor = new Color( shadowRGB | (((shadowAlpha / 2) & 0xff) << 24), true ); + Color endColor = new Color( shadowRGB, true ); + + int wh = (shadowSize * 2) - 1; + int center = shadowSize - 1; + + RadialGradientPaint p = new RadialGradientPaint( center, center, + shadowSize - (0.75f * scaleFactor), + new float[] { 0, 0.35f, 1 }, + new Color[] { startColor, midColor, endColor } ); + + BufferedImage image = new BufferedImage( wh, wh, BufferedImage.TYPE_INT_ARGB ); + + Graphics2D g = image.createGraphics(); + try { + g.setPaint( p ); + g.fillRect( 0, 0, wh, wh ); + } finally { + g.dispose(); + } + + return image; + } +} diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java index 5d60fd17..336dab6e 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java @@ -113,6 +113,8 @@ public class FlatInternalFrameUI private final Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" ); private final int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 ); + private final FlatDropShadowBorder dropShadowBorder = new FlatDropShadowBorder(); + public FlatInternalFrameBorder() { super( UIManager.getInsets( "InternalFrame.borderMargins" ) ); } @@ -137,16 +139,24 @@ public class FlatInternalFrameUI Insets insets = getBorderInsets( c ); float lineWidth = scale( (float) borderLineWidth ); + float rx = x + insets.left - lineWidth; + float ry = y + insets.top - lineWidth; + float rwidth = width - insets.left - insets.right + (lineWidth * 2); + float rheight = height - insets.top - insets.bottom + (lineWidth * 2); + Graphics2D g2 = (Graphics2D) g.create(); try { FlatUIUtils.setRenderingHints( g2 ); g2.setColor( f.isSelected() ? activeBorderColor : inactiveBorderColor ); - g2.fill( FlatUIUtils.createRectangle( - x + insets.left - lineWidth, - y + insets.top - lineWidth, - width - insets.left - insets.right + (lineWidth * 2), - height - insets.top - insets.bottom + (lineWidth * 2), - lineWidth ) ); + + // paint drop shadow + Insets dropShadowInsets = dropShadowBorder.getBorderInsets(); + dropShadowBorder.paintBorder( c, g2, (int) rx, (int) ry, + (int) rwidth + dropShadowInsets.right, + (int) rheight + dropShadowInsets.bottom ); + + // paint border + g2.fill( FlatUIUtils.createRectangle( rx, ry, rwidth, rheight, lineWidth ) ); } finally { g2.dispose(); } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties index db0c1d7d..34574c05 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties @@ -148,8 +148,8 @@ InternalFrame.activeTitleForeground=@foreground InternalFrame.inactiveTitleBackground=darken(@background,5%) InternalFrame.inactiveTitleForeground=@disabledText -InternalFrame.activeBorderColor=lighten($Component.borderColor,10%) -InternalFrame.inactiveBorderColor=$Component.borderColor +InternalFrame.activeBorderColor=darken(@background,7%) +InternalFrame.inactiveBorderColor=darken(@background,3%) InternalFrame.buttonHoverBackground=lighten($InternalFrame.activeTitleBackground,10%,derived autoInverse) InternalFrame.buttonPressedBackground=lighten($InternalFrame.activeTitleBackground,20%,derived autoInverse) diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt index 178761a8..88b6ed9d 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt @@ -327,7 +327,7 @@ HyperlinkUI com.formdev.flatlaf.swingx.ui.FlatHyperlinkUI #---- InternalFrame ---- -InternalFrame.activeBorderColor #7e7e7e javax.swing.plaf.ColorUIResource [UI] +InternalFrame.activeBorderColor #2b2d2e javax.swing.plaf.ColorUIResource [UI] InternalFrame.activeTitleBackground #242526 javax.swing.plaf.ColorUIResource [UI] InternalFrame.activeTitleForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] InternalFrame.border [lazy] 6,6,6,6 false com.formdev.flatlaf.ui.FlatInternalFrameUI$FlatInternalFrameBorder [UI] @@ -348,7 +348,7 @@ InternalFrame.closePressedBackground [lazy] #ad3b37 javax.swing.plaf.ColorUIR InternalFrame.closePressedForeground #ffffff javax.swing.plaf.ColorUIResource [UI] InternalFrame.icon [lazy] 16,16 sun.swing.ImageIconUIResource [UI] (sun.awt.image.ToolkitImage) InternalFrame.iconifyIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon [UI] -InternalFrame.inactiveBorderColor #646464 javax.swing.plaf.ColorUIResource [UI] +InternalFrame.inactiveBorderColor #353739 javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleBackground #303234 javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleForeground #777777 javax.swing.plaf.ColorUIResource [UI] InternalFrame.maximizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon [UI] diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt index 34c76c32..28d5d6be 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -326,7 +326,7 @@ HyperlinkUI com.formdev.flatlaf.swingx.ui.FlatHyperlinkUI #---- InternalFrame ---- -InternalFrame.activeBorderColor #7e7e7e javax.swing.plaf.ColorUIResource [UI] +InternalFrame.activeBorderColor #2b2d2e javax.swing.plaf.ColorUIResource [UI] InternalFrame.activeTitleBackground #242526 javax.swing.plaf.ColorUIResource [UI] InternalFrame.activeTitleForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] InternalFrame.border [lazy] 6,6,6,6 false com.formdev.flatlaf.ui.FlatInternalFrameUI$FlatInternalFrameBorder [UI] @@ -347,7 +347,7 @@ InternalFrame.closePressedBackground [lazy] #ad3b37 javax.swing.plaf.ColorUIR InternalFrame.closePressedForeground #ffffff javax.swing.plaf.ColorUIResource [UI] InternalFrame.icon [lazy] 16,16 sun.swing.ImageIconUIResource [UI] (sun.awt.image.ToolkitImage) InternalFrame.iconifyIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon [UI] -InternalFrame.inactiveBorderColor #646464 javax.swing.plaf.ColorUIResource [UI] +InternalFrame.inactiveBorderColor #353739 javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleBackground #303234 javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleForeground #777777 javax.swing.plaf.ColorUIResource [UI] InternalFrame.maximizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon [UI]