mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-08 15:00:54 +03:00
added simple UI inspector to FlatTestFrame
This commit is contained in:
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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
|
||||||
|
*
|
||||||
|
* http://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;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseMotionAdapter;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import javax.swing.AbstractButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JRootPane;
|
||||||
|
import javax.swing.JToolBar;
|
||||||
|
import javax.swing.JToolTip;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.plaf.UIResource;
|
||||||
|
import javax.swing.text.JTextComponent;
|
||||||
|
import com.formdev.flatlaf.ui.FlatToolTipUI;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class FlatInspector
|
||||||
|
{
|
||||||
|
private static final Integer HIGHLIGHT_LAYER = 401;
|
||||||
|
private static final Integer TOOLTIP_LAYER = 402;
|
||||||
|
|
||||||
|
private final JRootPane rootPane;
|
||||||
|
|
||||||
|
private Component lastComponent;
|
||||||
|
private int lastX;
|
||||||
|
private int lastY;
|
||||||
|
|
||||||
|
private JComponent highlightFigure;
|
||||||
|
private JToolTip tip;
|
||||||
|
|
||||||
|
public FlatInspector( JRootPane rootPane ) {
|
||||||
|
this.rootPane = rootPane;
|
||||||
|
|
||||||
|
rootPane.getGlassPane().addMouseMotionListener( new MouseMotionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseMoved( MouseEvent e ) {
|
||||||
|
lastX = e.getX();
|
||||||
|
lastY = e.getY();
|
||||||
|
inspect( lastX, lastY );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled( boolean enabled ) {
|
||||||
|
rootPane.getGlassPane().setVisible( enabled );
|
||||||
|
|
||||||
|
if( !enabled ) {
|
||||||
|
lastComponent = null;
|
||||||
|
|
||||||
|
if( highlightFigure != null )
|
||||||
|
highlightFigure.getParent().remove( highlightFigure );
|
||||||
|
highlightFigure = null;
|
||||||
|
|
||||||
|
if( tip != null )
|
||||||
|
tip.getParent().remove( tip );
|
||||||
|
tip = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
if( !rootPane.getGlassPane().isVisible() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventQueue.invokeLater( () -> {
|
||||||
|
setEnabled( false );
|
||||||
|
setEnabled( true );
|
||||||
|
inspect( lastX, lastY );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void inspect( int x, int y ) {
|
||||||
|
Container contentPane = rootPane.getContentPane();
|
||||||
|
Component c = SwingUtilities.getDeepestComponentAt( contentPane, x, y );
|
||||||
|
if( c == contentPane || c.getParent() == contentPane )
|
||||||
|
c = null;
|
||||||
|
|
||||||
|
if( c == lastComponent )
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastComponent = c;
|
||||||
|
|
||||||
|
highlight( c );
|
||||||
|
showToolTip( c, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void highlight( Component c ) {
|
||||||
|
if( highlightFigure == null ) {
|
||||||
|
highlightFigure = createHighlightFigure();
|
||||||
|
rootPane.getLayeredPane().add( highlightFigure, HIGHLIGHT_LAYER );
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightFigure.setVisible( c != null );
|
||||||
|
|
||||||
|
if( c != null ) {
|
||||||
|
Rectangle bounds = c.getBounds();
|
||||||
|
Rectangle highlightBounds = SwingUtilities.convertRectangle( c.getParent(), bounds, rootPane );
|
||||||
|
highlightFigure.setBounds( highlightBounds );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JComponent createHighlightFigure() {
|
||||||
|
JComponent c = new JComponent() {
|
||||||
|
@Override
|
||||||
|
protected void paintComponent( Graphics g ) {
|
||||||
|
g.setColor( getBackground() );
|
||||||
|
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
c.setBackground( new Color( 255, 0, 0, 32 ) );
|
||||||
|
c.setBorder( new LineBorder( Color.red ) );
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToolTip( Component c, int x, int y ) {
|
||||||
|
if( c == null ) {
|
||||||
|
if( tip != null )
|
||||||
|
tip.setVisible( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( tip == null ) {
|
||||||
|
tip = new JToolTip() {
|
||||||
|
@Override
|
||||||
|
public void updateUI() {
|
||||||
|
setUI( FlatToolTipUI.createUI( this ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rootPane.getLayeredPane().add( tip, TOOLTIP_LAYER );
|
||||||
|
} else
|
||||||
|
tip.setVisible( true );
|
||||||
|
|
||||||
|
tip.setTipText( buildToolTipText( c ) );
|
||||||
|
|
||||||
|
int tx = x + UIScale.scale( 8 );
|
||||||
|
int ty = y + UIScale.scale( 16 );
|
||||||
|
Dimension size = tip.getPreferredSize();
|
||||||
|
|
||||||
|
// position the tip in the visible area
|
||||||
|
Rectangle visibleRect = rootPane.getVisibleRect();
|
||||||
|
if( tx + size.width > visibleRect.x + visibleRect.width )
|
||||||
|
tx = visibleRect.x + visibleRect.width - size.width;
|
||||||
|
if( ty + size.height > visibleRect.y + visibleRect.height )
|
||||||
|
ty = visibleRect.y + visibleRect.height - size.height;
|
||||||
|
if( tx < visibleRect.x )
|
||||||
|
tx = visibleRect.x;
|
||||||
|
if( ty < visibleRect.y )
|
||||||
|
ty = visibleRect.y;
|
||||||
|
|
||||||
|
tip.setBounds( tx, ty, size.width, size.height );
|
||||||
|
tip.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildToolTipText( Component c ) {
|
||||||
|
String text =
|
||||||
|
"Class: " + c.getClass().getSimpleName() + " (" + c.getClass().getPackage().getName() + ")\n" +
|
||||||
|
"Size: " + c.getWidth() + ',' + c.getHeight() + " @ " + c.getX() + ',' + c.getY() + '\n';
|
||||||
|
|
||||||
|
if( c instanceof Container ) {
|
||||||
|
Insets i = ((Container)c).getInsets();
|
||||||
|
text += "Insets: " + i.top + ',' + i.left + ',' + i.bottom + ',' + i.right + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
Insets margin = null;
|
||||||
|
if( c instanceof AbstractButton )
|
||||||
|
margin = ((AbstractButton) c).getMargin();
|
||||||
|
else if( c instanceof JToolBar )
|
||||||
|
margin = ((JToolBar) c).getMargin();
|
||||||
|
else if( c instanceof JTextComponent )
|
||||||
|
margin = ((JTextComponent) c).getMargin();
|
||||||
|
|
||||||
|
if( margin != null )
|
||||||
|
text += "Margin: " + margin.top + ',' + margin.left + ',' + margin.bottom + ',' + margin.right + '\n';
|
||||||
|
|
||||||
|
Dimension prefSize = c.getPreferredSize();
|
||||||
|
Dimension minSize = c.getMinimumSize();
|
||||||
|
Dimension maxSize = c.getMaximumSize();
|
||||||
|
text += "Pref size: " + prefSize.width + ',' + prefSize.height + '\n' +
|
||||||
|
"Min size: " + minSize.width + ',' + minSize.height + '\n' +
|
||||||
|
"Max size: " + maxSize.width + ',' + maxSize.height + '\n';
|
||||||
|
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
Border border = ((JComponent)c).getBorder();
|
||||||
|
text += "Border: " + (border != null ? border.getClass().getName() : "null") + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
text += "Background: " + toString( c.getBackground() ) + '\n' +
|
||||||
|
"Foreground: " + toString( c.getForeground() ) + '\n' +
|
||||||
|
"Font: " + toString( c.getFont() ) + '\n';
|
||||||
|
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
try {
|
||||||
|
Field f = JComponent.class.getDeclaredField( "ui" );
|
||||||
|
f.setAccessible( true );
|
||||||
|
Object ui = f.get( c );
|
||||||
|
text += "UI: " + (ui != null ? ui.getClass().getName() : "null") + '\n';
|
||||||
|
} catch( NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text += "Parent: " + c.getParent().getClass().getName();
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toString( Color c ) {
|
||||||
|
if( c == null )
|
||||||
|
return "null";
|
||||||
|
|
||||||
|
String s = Long.toString( c.getRGB() & 0xffffffffl, 16 );
|
||||||
|
if( c instanceof UIResource )
|
||||||
|
s += " UI";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toString( Font f ) {
|
||||||
|
if( f == null )
|
||||||
|
return "null";
|
||||||
|
|
||||||
|
return f.getFamily() + " " + f.getSize() + " " + f.getStyle()
|
||||||
|
+ (f instanceof UIResource ? " UI" : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ public class FlatTestFrame
|
|||||||
private static final String KEY_LAF = "laf";
|
private static final String KEY_LAF = "laf";
|
||||||
|
|
||||||
private JComponent content;
|
private JComponent content;
|
||||||
|
private FlatInspector inspector;
|
||||||
|
|
||||||
public static FlatTestFrame create( String[] args, String title ) {
|
public static FlatTestFrame create( String[] args, String title ) {
|
||||||
// set look and feel
|
// set look and feel
|
||||||
@@ -143,7 +144,7 @@ public class FlatTestFrame
|
|||||||
protected void showFrame( JComponent content ) {
|
protected void showFrame( JComponent content ) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
|
|
||||||
contentPanel.add( content );
|
contentPanel.getContentPane().add( content );
|
||||||
pack();
|
pack();
|
||||||
setLocationRelativeTo( null );
|
setLocationRelativeTo( null );
|
||||||
setVisible( true );
|
setVisible( true );
|
||||||
@@ -185,6 +186,9 @@ public class FlatTestFrame
|
|||||||
if( prefSize.width > width || prefSize.height > height )
|
if( prefSize.width > width || prefSize.height > height )
|
||||||
setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
||||||
|
|
||||||
|
if( inspector != null )
|
||||||
|
inspector.update();
|
||||||
|
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -279,15 +283,22 @@ public class FlatTestFrame
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void inspectChanged() {
|
||||||
|
if( inspector == null )
|
||||||
|
inspector = new FlatInspector( contentPanel );
|
||||||
|
inspector.setEnabled( inspectCheckBox.isSelected() );
|
||||||
|
}
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
dialogPane = new JPanel();
|
dialogPane = new JPanel();
|
||||||
contentPanel = new JPanel();
|
contentPanel = new JRootPane();
|
||||||
buttonBar = new JPanel();
|
buttonBar = new JPanel();
|
||||||
lookAndFeelComboBox = new JComboBox<>();
|
lookAndFeelComboBox = new JComboBox<>();
|
||||||
explicitColorsCheckBox = new JCheckBox();
|
explicitColorsCheckBox = new JCheckBox();
|
||||||
rightToLeftCheckBox = new JCheckBox();
|
rightToLeftCheckBox = new JCheckBox();
|
||||||
enabledCheckBox = new JCheckBox();
|
enabledCheckBox = new JCheckBox();
|
||||||
|
inspectCheckBox = new JCheckBox();
|
||||||
closeButton = new JButton();
|
closeButton = new JButton();
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
@@ -301,7 +312,8 @@ public class FlatTestFrame
|
|||||||
|
|
||||||
//======== contentPanel ========
|
//======== contentPanel ========
|
||||||
{
|
{
|
||||||
contentPanel.setLayout(new MigLayout(
|
Container contentPanelContentPane = contentPanel.getContentPane();
|
||||||
|
contentPanelContentPane.setLayout(new MigLayout(
|
||||||
"insets dialog,hidemode 3",
|
"insets dialog,hidemode 3",
|
||||||
// columns
|
// columns
|
||||||
"[grow,fill]",
|
"[grow,fill]",
|
||||||
@@ -319,6 +331,7 @@ public class FlatTestFrame
|
|||||||
"[fill]" +
|
"[fill]" +
|
||||||
"[fill]" +
|
"[fill]" +
|
||||||
"[fill]" +
|
"[fill]" +
|
||||||
|
"[fill]" +
|
||||||
"[grow,fill]" +
|
"[grow,fill]" +
|
||||||
"[button,fill]",
|
"[button,fill]",
|
||||||
// rows
|
// rows
|
||||||
@@ -347,9 +360,15 @@ public class FlatTestFrame
|
|||||||
enabledCheckBox.addActionListener(e -> enabledChanged());
|
enabledCheckBox.addActionListener(e -> enabledChanged());
|
||||||
buttonBar.add(enabledCheckBox, "cell 3 0");
|
buttonBar.add(enabledCheckBox, "cell 3 0");
|
||||||
|
|
||||||
|
//---- inspectCheckBox ----
|
||||||
|
inspectCheckBox.setText("inspect");
|
||||||
|
inspectCheckBox.setMnemonic('I');
|
||||||
|
inspectCheckBox.addActionListener(e -> inspectChanged());
|
||||||
|
buttonBar.add(inspectCheckBox, "cell 4 0");
|
||||||
|
|
||||||
//---- closeButton ----
|
//---- closeButton ----
|
||||||
closeButton.setText("Close");
|
closeButton.setText("Close");
|
||||||
buttonBar.add(closeButton, "cell 5 0");
|
buttonBar.add(closeButton, "cell 6 0");
|
||||||
}
|
}
|
||||||
dialogPane.add(buttonBar, BorderLayout.SOUTH);
|
dialogPane.add(buttonBar, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
@@ -359,12 +378,13 @@ public class FlatTestFrame
|
|||||||
|
|
||||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||||
private JPanel dialogPane;
|
private JPanel dialogPane;
|
||||||
private JPanel contentPanel;
|
private JRootPane contentPanel;
|
||||||
private JPanel buttonBar;
|
private JPanel buttonBar;
|
||||||
private JComboBox<LafInfo> lookAndFeelComboBox;
|
private JComboBox<LafInfo> lookAndFeelComboBox;
|
||||||
private JCheckBox explicitColorsCheckBox;
|
private JCheckBox explicitColorsCheckBox;
|
||||||
private JCheckBox rightToLeftCheckBox;
|
private JCheckBox rightToLeftCheckBox;
|
||||||
private JCheckBox enabledCheckBox;
|
private JCheckBox enabledCheckBox;
|
||||||
|
private JCheckBox inspectCheckBox;
|
||||||
private JButton closeButton;
|
private JButton closeButton;
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ new FormModel {
|
|||||||
"defaultCloseOperation": 2
|
"defaultCloseOperation": 2
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||||
name: "dialogPane"
|
name: "dialogPane"
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JRootPane", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[grow,fill]"
|
"$columnConstraints": "[grow,fill]"
|
||||||
"$rowConstraints": "[grow,fill]"
|
"$rowConstraints": "[grow,fill]"
|
||||||
@@ -21,7 +21,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 dialog"
|
"$layoutConstraints": "insets dialog"
|
||||||
"$columnConstraints": "[fill][fill][fill][fill][grow,fill][button,fill]"
|
"$columnConstraints": "[fill][fill][fill][fill][fill][grow,fill][button,fill]"
|
||||||
"$rowSpecs": "[fill]"
|
"$rowSpecs": "[fill]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "buttonBar"
|
name: "buttonBar"
|
||||||
@@ -59,11 +59,19 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 3 0"
|
"value": "cell 3 0"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "inspectCheckBox"
|
||||||
|
"text": "inspect"
|
||||||
|
"mnemonic": 73
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "inspectChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 4 0"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JButton" ) {
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
name: "closeButton"
|
name: "closeButton"
|
||||||
"text": "Close"
|
"text": "Close"
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 5 0"
|
"value": "cell 6 0"
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
"value": "South"
|
"value": "South"
|
||||||
@@ -73,7 +81,7 @@ new FormModel {
|
|||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 400, 300 )
|
"size": new java.awt.Dimension( 510, 300 )
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user