mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-07 22:40:53 +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 JComponent content;
|
||||
private FlatInspector inspector;
|
||||
|
||||
public static FlatTestFrame create( String[] args, String title ) {
|
||||
// set look and feel
|
||||
@@ -143,7 +144,7 @@ public class FlatTestFrame
|
||||
protected void showFrame( JComponent content ) {
|
||||
this.content = content;
|
||||
|
||||
contentPanel.add( content );
|
||||
contentPanel.getContentPane().add( content );
|
||||
pack();
|
||||
setLocationRelativeTo( null );
|
||||
setVisible( true );
|
||||
@@ -185,6 +186,9 @@ public class FlatTestFrame
|
||||
if( prefSize.width > width || prefSize.height > height )
|
||||
setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
||||
|
||||
if( inspector != null )
|
||||
inspector.update();
|
||||
|
||||
} catch( Exception ex ) {
|
||||
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() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
dialogPane = new JPanel();
|
||||
contentPanel = new JPanel();
|
||||
contentPanel = new JRootPane();
|
||||
buttonBar = new JPanel();
|
||||
lookAndFeelComboBox = new JComboBox<>();
|
||||
explicitColorsCheckBox = new JCheckBox();
|
||||
rightToLeftCheckBox = new JCheckBox();
|
||||
enabledCheckBox = new JCheckBox();
|
||||
inspectCheckBox = new JCheckBox();
|
||||
closeButton = new JButton();
|
||||
|
||||
//======== this ========
|
||||
@@ -301,7 +312,8 @@ public class FlatTestFrame
|
||||
|
||||
//======== contentPanel ========
|
||||
{
|
||||
contentPanel.setLayout(new MigLayout(
|
||||
Container contentPanelContentPane = contentPanel.getContentPane();
|
||||
contentPanelContentPane.setLayout(new MigLayout(
|
||||
"insets dialog,hidemode 3",
|
||||
// columns
|
||||
"[grow,fill]",
|
||||
@@ -319,6 +331,7 @@ public class FlatTestFrame
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[grow,fill]" +
|
||||
"[button,fill]",
|
||||
// rows
|
||||
@@ -347,9 +360,15 @@ public class FlatTestFrame
|
||||
enabledCheckBox.addActionListener(e -> enabledChanged());
|
||||
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.setText("Close");
|
||||
buttonBar.add(closeButton, "cell 5 0");
|
||||
buttonBar.add(closeButton, "cell 6 0");
|
||||
}
|
||||
dialogPane.add(buttonBar, BorderLayout.SOUTH);
|
||||
}
|
||||
@@ -359,12 +378,13 @@ public class FlatTestFrame
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
private JPanel dialogPane;
|
||||
private JPanel contentPanel;
|
||||
private JRootPane contentPanel;
|
||||
private JPanel buttonBar;
|
||||
private JComboBox<LafInfo> lookAndFeelComboBox;
|
||||
private JCheckBox explicitColorsCheckBox;
|
||||
private JCheckBox rightToLeftCheckBox;
|
||||
private JCheckBox enabledCheckBox;
|
||||
private JCheckBox inspectCheckBox;
|
||||
private JButton closeButton;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ new FormModel {
|
||||
"defaultCloseOperation": 2
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||
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"
|
||||
"$columnConstraints": "[grow,fill]"
|
||||
"$rowConstraints": "[grow,fill]"
|
||||
@@ -21,7 +21,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets dialog"
|
||||
"$columnConstraints": "[fill][fill][fill][fill][grow,fill][button,fill]"
|
||||
"$columnConstraints": "[fill][fill][fill][fill][fill][grow,fill][button,fill]"
|
||||
"$rowSpecs": "[fill]"
|
||||
} ) {
|
||||
name: "buttonBar"
|
||||
@@ -59,11 +59,19 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"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" ) {
|
||||
name: "closeButton"
|
||||
"text": "Close"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 5 0"
|
||||
"value": "cell 6 0"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||
"value": "South"
|
||||
@@ -73,7 +81,7 @@ new FormModel {
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"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