diff --git a/CHANGELOG.md b/CHANGELOG.md index f90ca5e5..6f478494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ FlatLaf Change Log - Menu items "File > Open" and "File > Save As" now show file choosers. - InternalFrame: Support draggable border for resizing frame inside of the visible frame border. (issue #121) +- `FlatUIDefaultsInspector` added (see [FlatLaf Extras](flatlaf-extras)). A + simple UI defaults inspector that shows a window with all UI defaults used in + current theme (look and feel). #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledEmptyBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledEmptyBorder.java new file mode 100644 index 00000000..4d40e61e --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledEmptyBorder.java @@ -0,0 +1,53 @@ +/* + * 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.util; + +import static com.formdev.flatlaf.util.UIScale.scale; +import java.awt.Component; +import java.awt.Insets; +import javax.swing.border.EmptyBorder; + +/** + * Empty border that scales insets. + * + * @author Karl Tauber + */ +public class ScaledEmptyBorder + extends EmptyBorder +{ + public ScaledEmptyBorder( int top, int left, int bottom, int right ) { + super( top, left, bottom, right ); + } + + public ScaledEmptyBorder( Insets insets ) { + super( insets ); + } + + @Override + public Insets getBorderInsets() { + return new Insets( scale( top ), scale( left ), scale( bottom ), scale( right ) ); + } + + @Override + public Insets getBorderInsets( Component c, Insets insets ) { + insets.left = scale( left ); + insets.top = scale( top ); + insets.right = scale( right ); + insets.bottom = scale( bottom ); + return insets; + } +} diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index 70fc1748..8100f140 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -31,6 +31,7 @@ import com.formdev.flatlaf.demo.extras.*; import com.formdev.flatlaf.demo.intellijthemes.*; import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatSVGIcon; +import com.formdev.flatlaf.extras.FlatUIDefaultsInspector; import com.formdev.flatlaf.extras.SVGUtils; import com.formdev.flatlaf.ui.JBRCustomDecorations; import net.miginfocom.layout.ConstraintParser; @@ -93,6 +94,10 @@ class DemoFrame state.remove( "hint.themesPanel" ); } + private void showUIDefaultsInspector() { + FlatUIDefaultsInspector.show(); + } + private void openActionPerformed() { JFileChooser chooser = new JFileChooser(); chooser.showOpenDialog( this ); @@ -104,7 +109,7 @@ class DemoFrame } private void exitActionPerformed() { - dispose(); + System.exit( 0 ); } private void aboutActionPerformed() { @@ -308,6 +313,7 @@ class DemoFrame alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem(); animatedLafChangeMenuItem = new JCheckBoxMenuItem(); JMenuItem showHintsMenuItem = new JMenuItem(); + JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem(); JMenu helpMenu = new JMenu(); JMenuItem aboutMenuItem = new JMenuItem(); JToolBar toolBar1 = new JToolBar(); @@ -331,7 +337,7 @@ class DemoFrame //======== this ======== setTitle("FlatLaf Demo"); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); Container contentPane = getContentPane(); contentPane.setLayout(new BorderLayout()); @@ -579,6 +585,11 @@ class DemoFrame showHintsMenuItem.setText("Show hints"); showHintsMenuItem.addActionListener(e -> showHintsChanged()); optionsMenu.add(showHintsMenuItem); + + //---- showUIDefaultsInspectorMenuItem ---- + showUIDefaultsInspectorMenuItem.setText("Show UIDefaults Inspector"); + showUIDefaultsInspectorMenuItem.addActionListener(e -> showUIDefaultsInspector()); + optionsMenu.add(showUIDefaultsInspectorMenuItem); } menuBar1.add(optionsMenu); diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd index 13895915..f7cb04af 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd @@ -9,7 +9,7 @@ new FormModel { add( new FormWindow( "javax.swing.JFrame", new FormLayoutManager( class java.awt.BorderLayout ) ) { name: "this" "title": "FlatLaf Demo" - "defaultCloseOperation": 2 + "defaultCloseOperation": 3 "$locationPolicy": 2 "$sizePolicy": 2 add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { @@ -383,6 +383,11 @@ new FormModel { "text": "Show hints" addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHintsChanged", false ) ) } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "showUIDefaultsInspectorMenuItem" + "text": "Show UIDefaults Inspector" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showUIDefaultsInspector", false ) ) + } ) } ) add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { name: "helpMenu" diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/FlatLafDemo.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/FlatLafDemo.java index 38d0ef11..3e24a316 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/FlatLafDemo.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/FlatLafDemo.java @@ -22,6 +22,7 @@ import javax.swing.JFrame; import javax.swing.SwingUtilities; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.extras.FlatInspector; +import com.formdev.flatlaf.extras.FlatUIDefaultsInspector; import com.formdev.flatlaf.util.SystemInfo; /** @@ -52,8 +53,9 @@ public class FlatLafDemo // set look and feel DemoPrefs.initLaf( args ); - // install inspector + // install inspectors FlatInspector.install( "ctrl shift alt X" ); + FlatUIDefaultsInspector.install( "ctrl shift alt Y" ); // create frame DemoFrame frame = new DemoFrame(); diff --git a/flatlaf-extras/README.md b/flatlaf-extras/README.md index 42b0499e..c7bf8b80 100644 --- a/flatlaf-extras/README.md +++ b/flatlaf-extras/README.md @@ -11,6 +11,9 @@ This sub-project provides some additional components and classes: - [FlatSVGIcon](src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java): An icon that displays SVG using [svgSalamander](https://github.com/JFormDesigner/svgSalamander). +- [FlatUIDefaultsInspector](src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java): + A simple UI defaults inspector that shows a window with all UI defaults used + in current theme (look and feel). - [TriStateCheckBox](src/main/java/com/formdev/flatlaf/extras/TriStateCheckBox.java): A tri-state check box. diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java new file mode 100644 index 00000000..eff21202 --- /dev/null +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java @@ -0,0 +1,373 @@ +/* + * 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.extras; + +import java.awt.*; +import java.awt.event.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.prefs.Preferences; +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableColumnModel; +import com.formdev.flatlaf.util.HSLColor; +import com.formdev.flatlaf.util.ScaledEmptyBorder; +import com.formdev.flatlaf.util.UIScale; + +/** + * A simple UI defaults inspector that shows a window with all UI defaults used + * in current look and feel. + *
+ * To use it in an application install it with: + *
+ * FlatUIDefaultsInspector.install( "ctrl shift alt Y" ); + *+ * This can be done e.g. in the main() method and allows enabling (and disabling) + * the UI defaults inspector with the given keystroke. + * + * @author Karl Tauber + */ +public class FlatUIDefaultsInspector +{ + private static final int KEY_MODIFIERS_MASK = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK; + + private static FlatUIDefaultsInspector inspector; + + /** + * Installs a key listener into the application that allows enabling and disabling + * the UI inspector with the given keystroke (e.g. "ctrl shift alt Y"). + */ + public static void install( String activationKeys ) { + KeyStroke keyStroke = KeyStroke.getKeyStroke( activationKeys ); + Toolkit.getDefaultToolkit().addAWTEventListener( e -> { + if( e.getID() == KeyEvent.KEY_RELEASED && + ((KeyEvent)e).getKeyCode() == keyStroke.getKeyCode() && + (((KeyEvent)e).getModifiersEx() & KEY_MODIFIERS_MASK) == (keyStroke.getModifiers() & KEY_MODIFIERS_MASK) ) + { + show(); + } + }, AWTEvent.KEY_EVENT_MASK ); + } + + public static void show() { + if( inspector != null ) { + inspector.frame.toFront(); + return; + } + + inspector = new FlatUIDefaultsInspector(); + inspector.frame.setVisible( true ); + } + + public static void hide() { + if( inspector != null ) + inspector.frame.dispose(); + } + + private FlatUIDefaultsInspector() { + initComponents(); + + panel.setBorder( new ScaledEmptyBorder( 10, 10, 10, 10 ) ); + + // initialize table + Item[] items = getUIDefaultsItems(); + table.setModel( new ItemsTableModel( items ) ); + table.setDefaultRenderer( Item.class, new ValueRenderer() ); + + // restore window bounds + Preferences prefs = getPrefs(); + int x = prefs.getInt( "x", -1 ); + int y = prefs.getInt( "y", -1 ); + int width = prefs.getInt( "width", UIScale.scale( 600 ) ); + int height = prefs.getInt( "height", UIScale.scale( 800 ) ); + frame.setSize( width, height ); + if( x >= 0 && y >= 0 ) + frame.setLocation( x, y ); + else + frame.setLocationRelativeTo( null ); + + // restore column widths + TableColumnModel columnModel = table.getColumnModel(); + columnModel.getColumn( 0 ).setPreferredWidth( prefs.getInt( "column1width", 100 ) ); + columnModel.getColumn( 1 ).setPreferredWidth( prefs.getInt( "column2width", 100 ) ); + } + + private Item[] getUIDefaultsItems() { + UIDefaults defaults = UIManager.getDefaults(); + + ArrayList