Window decorations: added window icon (issues #47 and #82)

This commit is contained in:
Karl Tauber
2020-05-27 11:36:11 +02:00
parent 9ad32125c0
commit 626601f6aa
13 changed files with 286 additions and 16 deletions

View File

@@ -19,8 +19,10 @@ package com.formdev.flatlaf.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
@@ -29,6 +31,7 @@ import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.accessibility.AccessibleContext;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
@@ -39,7 +42,6 @@ import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF title bar.
@@ -48,6 +50,9 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.inactiveBackground Color
* @uiDefault TitlePane.foreground Color
* @uiDefault TitlePane.inactiveForeground Color
* @uiDefault TitlePane.iconSize Dimension
* @uiDefault TitlePane.iconMargins Insets
* @uiDefault TitlePane.titleMargins Insets
* @uiDefault TitlePane.closeIcon Icon
* @uiDefault TitlePane.iconifyIcon Icon
* @uiDefault TitlePane.maximizeIcon Icon
@@ -63,8 +68,11 @@ class FlatTitlePane
private final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
private final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
private final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
private final JRootPane rootPane;
private JLabel iconLabel;
private JLabel titleLabel;
private JPanel buttonPanel;
private JButton iconifyButton;
@@ -85,12 +93,15 @@ class FlatTitlePane
}
private void addSubComponents() {
iconLabel = new JLabel();
titleLabel = new JLabel();
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
createButtons();
setLayout( new BorderLayout( UIScale.scale( 4 ), 0 ) );
setLayout( new BorderLayout() );
add( iconLabel, BorderLayout.WEST );
add( titleLabel, BorderLayout.CENTER );
add( buttonPanel, BorderLayout.EAST );
}
@@ -157,6 +168,26 @@ class FlatTitlePane
}
}
private void updateIcon() {
// get window images
List<Image> images = window.getIconImages();
if( images.isEmpty() ) {
// search in owners
for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) {
images = owner.getIconImages();
if( !images.isEmpty() )
break;
}
}
// show/hide icon
boolean hasImages = !images.isEmpty();
iconLabel.setVisible( hasImages );
if( hasImages )
iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) );
}
@Override
public void addNotify() {
super.addNotify();
@@ -167,6 +198,7 @@ class FlatTitlePane
if( window != null ) {
frameStateChanged();
activeChanged( window.isActive() );
updateIcon();
titleLabel.setText( getWindowTitle() );
installWindowListeners();
}
@@ -260,6 +292,10 @@ class FlatTitlePane
if( window instanceof Frame )
frameStateChanged();
break;
case "iconImage":
updateIcon();
break;
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.Dimension;
import java.awt.Image;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.ScaledImageIcon;
/**
* @author Karl Tauber
*/
class FlatTitlePaneIcon
extends ScaledImageIcon
{
static Icon create( List<Image> images, Dimension size ) {
// collect all images including multi-resolution variants
List<Image> allImages = new ArrayList<>();
for( Image image : images ) {
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) );
else
allImages.add( image );
}
// sort images by size
allImages.sort( (image1, image2) -> {
return image1.getWidth( null ) - image2.getWidth( null );
} );
// create icon
return new FlatTitlePaneIcon( allImages, size );
}
private final List<Image> images;
FlatTitlePaneIcon( List<Image> images, Dimension size ) {
super( new ImageIcon( images.get( 0 ) ), size.width, size.height );
this.images = images;
}
@Override
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
for( Image image : images ) {
if( destImageWidth <= image.getWidth( null ) &&
destImageHeight <= image.getHeight( null ) )
return image;
}
return images.get( images.size() - 1 );
}
}

View File

@@ -37,30 +37,38 @@ public class ScaledImageIcon
implements Icon
{
private final ImageIcon imageIcon;
private final int iconWidth;
private final int iconHeight;
private double lastSystemScaleFactor;
private float lastUserScaleFactor;
private Image lastImage;
public ScaledImageIcon( ImageIcon imageIcon ) {
this( imageIcon, imageIcon.getIconWidth(), imageIcon.getIconHeight() );
}
public ScaledImageIcon( ImageIcon imageIcon, int iconWidth, int iconHeight ) {
this.imageIcon = imageIcon;
this.iconWidth = iconWidth;
this.iconHeight = iconHeight;
}
@Override
public int getIconWidth() {
return UIScale.scale( imageIcon.getIconWidth() );
return UIScale.scale( iconWidth );
}
@Override
public int getIconHeight() {
return UIScale.scale( imageIcon.getIconHeight() );
return UIScale.scale( iconHeight );
}
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
/*debug
g.setColor( Color.red );
g.drawRect( x, y, getIconWidth(), getIconHeight() );
g.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
debug*/
// scale factor
@@ -69,7 +77,7 @@ debug*/
double scaleFactor = systemScaleFactor * userScaleFactor;
// paint input image icon if not necessary to scale
if( scaleFactor == 1 ) {
if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
imageIcon.paintIcon( c, g, x, y );
return;
}
@@ -84,12 +92,11 @@ debug*/
}
// destination image size
int destImageWidth = (int) Math.round( imageIcon.getIconWidth() * scaleFactor );
int destImageHeight = (int) Math.round( imageIcon.getIconHeight() * scaleFactor );
int destImageWidth = (int) Math.round( iconWidth * scaleFactor );
int destImageHeight = (int) Math.round( iconHeight * scaleFactor );
// get resolution variant of image if it is a multi-resolution image
Image image = MultiResolutionImageSupport.getResolutionVariant(
imageIcon.getImage(), destImageWidth, destImageHeight );
Image image = getResolutionVariant( destImageWidth, destImageHeight );
// size of image
int imageWidth = image.getWidth( null );
@@ -124,6 +131,11 @@ debug*/
paintLastImage( g, x, y );
}
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
return MultiResolutionImageSupport.getResolutionVariant(
imageIcon.getImage(), destImageWidth, destImageHeight );
}
private void paintLastImage( Graphics g, int x, int y ) {
if( lastSystemScaleFactor > 1 ) {
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used

View File

@@ -576,6 +576,8 @@ TitledBorder.border=1,1,1,1,$Separator.foreground
#---- TitlePane ----
TitlePane.iconSize=16,16
TitlePane.iconMargins=3,8,3,0
TitlePane.titleMargins=3,8,3,8
TitlePane.closeIcon=$InternalFrame.closeIcon
TitlePane.iconifyIcon=$InternalFrame.iconifyIcon