Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ToolBar: hover effect for button groups #534

Merged
merged 1 commit into from Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -704,5 +707,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 @@ -323,6 +341,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 @@ -840,6 +840,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 @@ -881,6 +881,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 @@ -1084,6 +1084,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 @@ -1303,6 +1303,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