Demo: show hint popups to guide users to some features of the FlatLaf Demo application; added "Options > Show hints" menu item

This commit is contained in:
Karl Tauber
2020-08-26 23:15:41 +02:00
parent af5a0ec0b7
commit 21d78671d6
8 changed files with 351 additions and 3 deletions

View File

@@ -20,11 +20,13 @@ import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.StyleContext;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.demo.HintManager.Hint;
import com.formdev.flatlaf.demo.extras.*;
import com.formdev.flatlaf.demo.intellijthemes.*;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
@@ -57,6 +59,35 @@ class DemoFrame
if( tabIndex >= 0 && tabIndex < tabbedPane.getTabCount() && tabIndex != tabbedPane.getSelectedIndex() )
tabbedPane.setSelectedIndex( tabIndex );
SwingUtilities.invokeLater( () -> {
showHints();
} );
}
private void showHints() {
Hint fontMenuHint = new Hint(
"Use 'Font' menu to increase/decrease font size or try different fonts.",
fontMenu, SwingConstants.BOTTOM, "hint.fontMenu", null );
Hint optionsMenuHint = new Hint(
"Use 'Options' menu to try out various FlatLaf options.",
optionsMenu, SwingConstants.BOTTOM, "hint.optionsMenu", fontMenuHint );
Hint themesHint = new Hint(
"Use 'Themes' list to try out various themes.",
themesPanel, SwingConstants.LEFT, "hint.themesPanel", optionsMenuHint );
HintManager.showHint( themesHint );
}
private void clearHints() {
HintManager.hideAllHints();
Preferences state = DemoPrefs.getState();
state.remove( "hint.fontMenu" );
state.remove( "hint.optionsMenu" );
state.remove( "hint.themesPanel" );
}
private void exitActionPerformed() {
@@ -110,6 +141,11 @@ class DemoFrame
System.setProperty( "flatlaf.animatedLafChange", String.valueOf( animatedLafChangeMenuItem.isSelected() ) );
}
private void showHintsChanged() {
clearHints();
showHints();
}
private void fontFamilyChanged( ActionEvent e ) {
String fontFamily = e.getActionCommand();
@@ -251,12 +287,13 @@ class DemoFrame
JMenuItem restoreFontMenuItem = new JMenuItem();
JMenuItem incrFontMenuItem = new JMenuItem();
JMenuItem decrFontMenuItem = new JMenuItem();
JMenu optionsMenu = new JMenu();
optionsMenu = new JMenu();
windowDecorationsCheckBoxMenuItem = new JCheckBoxMenuItem();
menuBarEmbeddedCheckBoxMenuItem = new JCheckBoxMenuItem();
underlineMenuSelectionMenuItem = new JCheckBoxMenuItem();
alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem();
animatedLafChangeMenuItem = new JCheckBoxMenuItem();
JMenuItem showHintsMenuItem = new JMenuItem();
JMenu helpMenu = new JMenu();
JMenuItem aboutMenuItem = new JMenuItem();
JToolBar toolBar1 = new JToolBar();
@@ -276,7 +313,7 @@ class DemoFrame
OptionPanePanel optionPanePanel = new OptionPanePanel();
ExtrasPanel extrasPanel1 = new ExtrasPanel();
controlBar = new ControlBar();
IJThemesPanel themesPanel = new IJThemesPanel();
themesPanel = new IJThemesPanel();
//======== this ========
setTitle("FlatLaf Demo");
@@ -516,6 +553,11 @@ class DemoFrame
animatedLafChangeMenuItem.setSelected(true);
animatedLafChangeMenuItem.addActionListener(e -> animatedLafChangeChanged());
optionsMenu.add(animatedLafChangeMenuItem);
//---- showHintsMenuItem ----
showHintsMenuItem.setText("Show hints");
showHintsMenuItem.addActionListener(e -> showHintsChanged());
optionsMenu.add(showHintsMenuItem);
}
menuBar1.add(optionsMenu);
@@ -631,6 +673,7 @@ class DemoFrame
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenu fontMenu;
private JMenu optionsMenu;
private JCheckBoxMenuItem windowDecorationsCheckBoxMenuItem;
private JCheckBoxMenuItem menuBarEmbeddedCheckBoxMenuItem;
private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
@@ -638,5 +681,6 @@ class DemoFrame
private JCheckBoxMenuItem animatedLafChangeMenuItem;
private JTabbedPane tabbedPane;
private ControlBar controlBar;
private IJThemesPanel themesPanel;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14.0.2" encoding: "UTF-8"
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -114,6 +114,9 @@ new FormModel {
} )
add( new FormComponent( "com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel" ) {
name: "themesPanel"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "East"
} )
@@ -322,6 +325,9 @@ new FormModel {
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "optionsMenu"
"text": "Options"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "windowDecorationsCheckBoxMenuItem"
"text": "Window decorations"
@@ -365,6 +371,11 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "animatedLafChangeChanged", false ) )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "showHintsMenuItem"
"text": "Show hints"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHintsChanged", false ) )
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "helpMenu"

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.demo;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.extras.FlatInspector;
import com.formdev.flatlaf.util.SystemInfo;
@@ -42,6 +43,9 @@ public class FlatLafDemo
JFrame.setDefaultLookAndFeelDecorated( true );
JDialog.setDefaultLookAndFeelDecorated( true );
// application specific UI defaults
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
// set look and feel
DemoPrefs.initLaf( args );

View File

@@ -0,0 +1,219 @@
/*
* 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.demo;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import com.formdev.flatlaf.ui.FlatDropShadowBorder;
import com.formdev.flatlaf.ui.FlatPopupMenuBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
class HintManager
{
private static final List<HintPanel> hintPanels = new ArrayList<>();
static void showHint( Hint hint ) {
// check whether user already closed the hint
if( DemoPrefs.getState().getBoolean( hint.prefsKey, false ) ) {
if( hint.nextHint != null )
showHint( hint.nextHint );
return;
}
HintPanel hintPanel = new HintPanel( hint );
hintPanel.showHint();
hintPanels.add( hintPanel );
}
static void hideAllHints() {
HintPanel[] hintPanels2 = hintPanels.toArray( new HintPanel[hintPanels.size()] );
for( HintPanel hintPanel : hintPanels2 )
hintPanel.hideHint();
}
//---- class HintPanel ----------------------------------------------------
static class Hint
{
private final String message;
private final Component owner;
private final int position;
private final String prefsKey;
private final Hint nextHint;
Hint( String message, Component owner, int position, String prefsKey, Hint nextHint ) {
this.message = message;
this.owner = owner;
this.position = position;
this.prefsKey = prefsKey;
this.nextHint = nextHint;
}
}
//---- class HintPanel ----------------------------------------------------
private static class HintPanel
extends JPanel
{
private final Hint hint;
private JPanel popup;
private HintPanel( Hint hint ) {
this.hint = hint;
initComponents();
hintLabel.setText( "<html>" + hint.message + "</html>" );
// grab all mouse events to avoid that components overlapped
// by the hint panel receive them
addMouseListener( new MouseAdapter() {} );
}
@Override
public void updateUI() {
super.updateUI();
setBackground( UIManager.getColor( "HintPanel.backgroundColor" ) );
setBorder( new FlatPopupMenuBorder() );
}
void showHint() {
JRootPane rootPane = SwingUtilities.getRootPane( hint.owner );
if( rootPane == null )
return;
JLayeredPane layeredPane = rootPane.getLayeredPane();
// create a popup panel that has a drop shadow
popup = new JPanel( new BorderLayout() ) {
@Override
public void updateUI() {
super.updateUI();
setBorder( new FlatDropShadowBorder(
UIManager.getColor( "Popup.dropShadowColor" ),
UIManager.getInsets( "Popup.dropShadowInsets" ),
FlatUIUtils.getUIFloat( "Popup.dropShadowOpacity", 0.5f ) ) );
// use invokeLater because at this time the UI delegates
// of child components are not yet updated
EventQueue.invokeLater( () -> {
validate();
setSize( getPreferredSize() );
} );
}
};
popup.setOpaque( false );
popup.add( this );
// calculate x/y location for hint popup
Point pt = SwingUtilities.convertPoint( hint.owner, 0, 0, layeredPane );
int x = pt.x;
int y = pt.y;
Dimension size = popup.getPreferredSize();
int gap = UIScale.scale( 6 );
switch( hint.position ) {
case SwingConstants.LEFT:
x -= size.width + gap;
break;
case SwingConstants.TOP:
y -= size.height + gap;
break;
case SwingConstants.RIGHT:
x += hint.owner.getWidth() + gap;
break;
case SwingConstants.BOTTOM:
y += hint.owner.getHeight() + gap;
break;
}
// set hint popup size and show it
popup.setBounds( x, y, size.width, size.height );
layeredPane.add( popup, JLayeredPane.POPUP_LAYER );
}
void hideHint() {
if( popup != null ) {
Container parent = popup.getParent();
if( parent != null ) {
parent.remove( popup );
parent.repaint( popup.getX(), popup.getY(), popup.getWidth(), popup.getHeight() );
}
}
hintPanels.remove( this );
}
private void gotIt() {
// hide hint
hideHint();
// remember that user closed the hint
DemoPrefs.getState().putBoolean( hint.prefsKey, true );
// show next hint (if any)
if( hint.nextHint != null )
HintManager.showHint( hint.nextHint );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
hintLabel = new JLabel();
gotItButton = new JButton();
//======== this ========
setLayout(new MigLayout(
"insets dialog,hidemode 3",
// columns
"[::200,fill]",
// rows
"[]para" +
"[]"));
//---- hintLabel ----
hintLabel.setText("hint");
add(hintLabel, "cell 0 0");
//---- gotItButton ----
gotItButton.setText("Got it!");
gotItButton.setFocusable(false);
gotItButton.addActionListener(e -> gotIt());
add(gotItButton, "cell 0 1,alignx right,growx 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JLabel hintLabel;
private JButton gotItButton;
// JFormDesigner - End of variables declaration //GEN-END:variables
}
}

View File

@@ -0,0 +1,34 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[::200,fill]"
"$rowConstraints": "[]para[]"
} ) {
name: "panel"
auxiliary() {
"JavaCodeGenerator.className": "HintPanel"
}
add( new FormComponent( "javax.swing.JLabel" ) {
name: "hintLabel"
"text": "hint"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "gotItButton"
"text": "Got it!"
"focusable": false
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "gotIt", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1,alignx right,growx 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 400, 300 )
} )
}
}

View File

@@ -0,0 +1,17 @@
#
# 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.
#
HintPanel.backgroundColor=darken(#ffffe1,80%)

View File

@@ -0,0 +1,17 @@
#
# 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.
#
HintPanel.backgroundColor=#ffffe1