Skip to content

Commit

Permalink
Merge PR #534: ToolBar: hover effect for button groups
Browse files Browse the repository at this point in the history
  • Loading branch information
DevCharly committed Oct 29, 2022
2 parents 9d8ffec + 2ef6a2c commit 607b084
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 16 deletions.
Expand Up @@ -20,6 +20,7 @@
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
Expand All @@ -45,8 +46,10 @@
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI;
Expand Down Expand Up @@ -797,5 +800,20 @@ public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}

@Override
public void stateChanged( ChangeEvent e ) {
super.stateChanged( e );

// if button is in toolbar, repaint button groups
AbstractButton b = (AbstractButton) e.getSource();
Container parent = b.getParent();
if( parent instanceof JToolBar ) {
JToolBar toolBar = (JToolBar) parent;
ToolBarUI ui = toolBar.getUI();
if( ui instanceof FlatToolBarUI )
((FlatToolBarUI)ui).repaintButtonGroup( b );
}
}
}
}
111 changes: 111 additions & 0 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java
Expand Up @@ -20,15 +20,24 @@
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.DefaultButtonModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.UIManager;
import javax.swing.border.Border;
Expand All @@ -37,6 +46,7 @@
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;

/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}.
Expand All @@ -58,6 +68,8 @@
* @uiDefault ToolBar.focusableButtons boolean
* @uiDefault ToolBar.arrowKeysOnlyNavigation boolean
* @uiDefault ToolBar.floatable boolean
* @uiDefault ToolBar.hoverButtonGroupArc int
* @uiDefault ToolBar.hoverButtonGroupBackground Color
*
* <!-- FlatToolBarBorder -->
*
Expand All @@ -72,6 +84,8 @@ public class FlatToolBarUI
{
/** @since 1.4 */ @Styleable protected boolean focusableButtons;
/** @since 2 */ @Styleable protected boolean arrowKeysOnlyNavigation;
/** @since 3 */ @Styleable protected int hoverButtonGroupArc;
/** @since 3 */ @Styleable protected Color hoverButtonGroupBackground;

// for FlatToolBarBorder
@Styleable protected Insets borderMargins;
Expand Down Expand Up @@ -119,6 +133,8 @@ protected void installDefaults() {

focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
arrowKeysOnlyNavigation = UIManager.getBoolean( "ToolBar.arrowKeysOnlyNavigation" );
hoverButtonGroupArc = UIManager.getInt( "ToolBar.hoverButtonGroupArc" );
hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" );

// floatable
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
Expand All @@ -132,6 +148,8 @@ protected void installDefaults() {
protected void uninstallDefaults() {
super.uninstallDefaults();

hoverButtonGroupBackground = null;

if( oldFloatable != null ) {
toolBar.setFloatable( oldFloatable );
oldFloatable = null;
Expand Down Expand Up @@ -329,6 +347,99 @@ public void setOrientation( int orientation ) {
super.setOrientation( orientation );
}

@Override
public void paint( Graphics g, JComponent c ) {
super.paint( g, c );

paintButtonGroup( g );
}

/**@since 3 */
protected void paintButtonGroup( Graphics g ) {
if( hoverButtonGroupBackground == null )
return;

// find hovered button that is part of a button group
ButtonGroup group = null;
for( Component b : toolBar.getComponents() ) {
if( b instanceof AbstractButton && ((AbstractButton)b).getModel().isRollover() ) {
group = getButtonGroup( (AbstractButton) b );
if( group != null )
break;
}
}
if( group == null )
return;

// get bounds of buttons in group
ArrayList<Rectangle> rects = new ArrayList<>();
Enumeration<AbstractButton> e = group.getElements();
while( e.hasMoreElements() ) {
AbstractButton gb = e.nextElement();
if( gb.getParent() == toolBar )
rects.add( gb.getBounds() );
}

// sort button bounds
boolean horizontal = (toolBar.getOrientation() == JToolBar.HORIZONTAL);
rects.sort( (r1, r2) -> horizontal ? r1.x - r2.x : r1.y - r2.y );

Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
g.setColor( FlatUIUtils.deriveColor( hoverButtonGroupBackground, toolBar.getBackground() ) );

// paint button group hover background
int maxSepWidth = UIScale.scale( 10 );
Rectangle gr = null;
for( Rectangle r : rects ) {
if( gr == null ) {
// first button
gr = r;
} else if( horizontal ? (gr.x + gr.width + maxSepWidth >= r.x) : (gr.y + gr.height + maxSepWidth >= r.y) ) {
// button joins previous button
gr = gr.union( r );
} else {
// paint group
FlatUIUtils.paintComponentBackground( (Graphics2D) g, gr.x, gr.y, gr.width, gr.height, 0, UIScale.scale( hoverButtonGroupArc ) );
gr = r;
}
}
if( gr != null )
FlatUIUtils.paintComponentBackground( (Graphics2D) g, gr.x, gr.y, gr.width, gr.height, 0, UIScale.scale( hoverButtonGroupArc ) );

FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}

/**@since 3 */
protected void repaintButtonGroup( AbstractButton b ) {
if( hoverButtonGroupBackground == null )
return;

ButtonGroup group = getButtonGroup( b );
if( group == null )
return;

// compute union bounds of all buttons in group (including separators)
Rectangle gr = null;
Enumeration<AbstractButton> e = group.getElements();
while( e.hasMoreElements() ) {
AbstractButton gb = e.nextElement();
Container parent = gb.getParent();
if( parent == toolBar )
gr = (gr != null) ? gr.union( gb.getBounds() ) : gb.getBounds();
}

// repaint button group
if( gr != null )
toolBar.repaint( gr );
}

private ButtonGroup getButtonGroup( AbstractButton b ) {
ButtonModel model = b.getModel();
return (model instanceof DefaultButtonModel)
? ((DefaultButtonModel)model).getGroup()
: null;
}

//---- class FlatToolBarFocusTraversalPolicy ------------------------------

/**
Expand Down
Expand Up @@ -349,6 +349,11 @@ ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,3%,de
ToggleButton.toolbar.selectedBackground = lighten($ToggleButton.background,7%,derived)


#---- ToolBar ----

ToolBar.hoverButtonGroupBackground = lighten($ToolBar.background,3%,derived)


#---- ToolTip ----

ToolTip.border = 4,6,4,6
Expand Down
Expand Up @@ -847,6 +847,7 @@ ToolBar.borderMargins = 2,2,2,2
ToolBar.isRollover = true
ToolBar.focusableButtons = false
ToolBar.arrowKeysOnlyNavigation = true
ToolBar.hoverButtonGroupArc = 8
ToolBar.floatable = false
ToolBar.gripColor = @icon
ToolBar.dockingBackground = darken($ToolBar.background,5%)
Expand Down
Expand Up @@ -356,6 +356,11 @@ ToggleButton.disabledSelectedBackground = darken($ToggleButton.background,13%,de
ToggleButton.toolbar.selectedBackground = $ToggleButton.selectedBackground


#---- ToolBar ----

ToolBar.hoverButtonGroupBackground = darken($ToolBar.background,3%,derived)


#---- ToolTip ----

ToolTip.border = 4,6,4,6,shade(@background,40%)
Expand Down
Expand Up @@ -899,6 +899,8 @@ void toolBar() {
Map<String, Class<?>> expected = expectedMap(
"focusableButtons", boolean.class,
"arrowKeysOnlyNavigation", boolean.class,
"hoverButtonGroupArc", int.class,
"hoverButtonGroupBackground", Color.class,

"borderMargins", Insets.class,
"gripColor", Color.class
Expand Down
Expand Up @@ -1102,6 +1102,8 @@ void toolBar() {

ui.applyStyle( "focusableButtons: true" );
ui.applyStyle( "arrowKeysOnlyNavigation: true" );
ui.applyStyle( "hoverButtonGroupArc: 12" );
ui.applyStyle( "hoverButtonGroupBackground: #fff" );

ui.applyStyle( "borderMargins: 1,2,3,4" );
ui.applyStyle( "gripColor: #fff" );
Expand Down
Expand Up @@ -101,6 +101,11 @@ private void initComponents() {
JButton button8 = new JButton();
JToggleButton toggleButton6 = new JToggleButton();
JButton button1 = new JButton();
JLabel label7 = new JLabel();
JToggleButton toggleButton1 = new JToggleButton();
JToggleButton toggleButton2 = new JToggleButton();
JToggleButton toggleButton3 = new JToggleButton();
JToggleButton toggleButton4 = new JToggleButton();
JLabel splitPaneLabel = new JLabel();
JSplitPane splitPane3 = new JSplitPane();
JSplitPane splitPane1 = new JSplitPane();
Expand Down Expand Up @@ -397,8 +402,30 @@ private void initComponents() {
button1.setIcon(new ImageIcon(getClass().getResource("/com/formdev/flatlaf/demo/icons/intellij-showWriteAccess.png")));
button1.setEnabled(false);
toolBar1.add(button1);
toolBar1.addSeparator();

//---- label7 ----
label7.setText("Button group hover:");
toolBar1.add(label7);

//---- toggleButton1 ----
toggleButton1.setIcon(UIManager.getIcon("FileView.computerIcon"));
toggleButton1.setSelected(true);
toolBar1.add(toggleButton1);

//---- toggleButton2 ----
toggleButton2.setIcon(UIManager.getIcon("FileView.computerIcon"));
toolBar1.add(toggleButton2);

//---- toggleButton3 ----
toggleButton3.setIcon(UIManager.getIcon("FileView.computerIcon"));
toolBar1.add(toggleButton3);

//---- toggleButton4 ----
toggleButton4.setIcon(UIManager.getIcon("FileView.computerIcon"));
toolBar1.add(toggleButton4);
}
add(toolBar1, "cell 1 10 3 1,growx");
add(toolBar1, "cell 1 10 4 1,growx");

//---- splitPaneLabel ----
splitPaneLabel.setText("JSplitPane:");
Expand Down Expand Up @@ -474,6 +501,13 @@ private void initComponents() {
splitPane3.setRightComponent(splitPane2);
}
add(splitPane3, "cell 1 11 4 1,grow");

//---- buttonGroup1 ----
ButtonGroup buttonGroup1 = new ButtonGroup();
buttonGroup1.add(toggleButton1);
buttonGroup1.add(toggleButton2);
buttonGroup1.add(toggleButton3);
buttonGroup1.add(toggleButton4);
// JFormDesigner - End of component initialization //GEN-END:initComponents

if( FlatLafDemo.screenshotsMode ) {
Expand Down
@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8"
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"

new FormModel {
contentType: "form/swing"
Expand Down Expand Up @@ -355,8 +355,36 @@ new FormModel {
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/intellij-showWriteAccess.png" )
"enabled": false
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator6"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label7"
"text": "Button group hover:"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "toggleButton1"
"icon": &SwingIcon3 new com.jformdesigner.model.SwingIcon( 2, "FileView.computerIcon" )
"$buttonGroup": new FormReference( "buttonGroup1" )
"selected": true
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "toggleButton2"
"icon": #SwingIcon3
"$buttonGroup": new FormReference( "buttonGroup1" )
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "toggleButton3"
"icon": #SwingIcon3
"$buttonGroup": new FormReference( "buttonGroup1" )
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "toggleButton4"
"icon": #SwingIcon3
"$buttonGroup": new FormReference( "buttonGroup1" )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 10 3 1,growx"
"value": "cell 1 10 4 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "splitPaneLabel"
Expand Down Expand Up @@ -443,5 +471,10 @@ new FormModel {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 700, 550 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "buttonGroup1"
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 560 )
} )
}
}
Expand Up @@ -218,6 +218,11 @@ ToggleButton.toolbar.selectedBackground = ToggleButton.background
ToggleButton.tab.hoverBackground = null


#---- ToolBar ----

ToolBar.hoverButtonGroupBackground = ToolBar.background




#---- JideButton ----
Expand Down
2 changes: 2 additions & 0 deletions flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
Expand Up @@ -1311,6 +1311,8 @@ ToolBar.font [active] $defaultFont [UI]
ToolBar.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
ToolBar.gripColor #aeaeae HSL 0 0 68 javax.swing.plaf.ColorUIResource [UI]
ToolBar.highlight #232324 HSL 240 1 14 javax.swing.plaf.ColorUIResource [UI]
ToolBar.hoverButtonGroupArc 8
ToolBar.hoverButtonGroupBackground #434749 HSL 200 4 27 com.formdev.flatlaf.util.DerivedColor [UI] lighten(3% autoInverse)
ToolBar.isRollover true
ToolBar.light #2f3031 HSL 210 2 19 javax.swing.plaf.ColorUIResource [UI]
ToolBar.separatorColor #505254 HSL 210 2 32 javax.swing.plaf.ColorUIResource [UI]
Expand Down

0 comments on commit 607b084

Please sign in to comment.