Skip to content

Commit

Permalink
ToolBar: support arrow-keys-only navigation within focusable buttons …
Browse files Browse the repository at this point in the history
…of toolbar:

- arrow keys move focus within toolbar (provided by `BasicToolBarUI`)
- tab-key moves focus out of toolbar
- if moving focus into the toolbar, focus recently focused toolbar button

(issue #346)
  • Loading branch information
DevCharly committed Oct 5, 2021
1 parent 1e93dea commit 69042e4
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ FlatLaf Change Log
- Skip components with empty input map (e.g. `JLabel`) when using arrow keys
to navigate in focusable buttons (if UI value `ToolBar.focusableButtons` is
`true`).
- Support arrow-keys-only navigation within focusable buttons of toolbar (if
UI value `ToolBar.focusableButtons` is `true`):
- arrow keys move focus within toolbar
- tab-key moves focus out of toolbar
- if moving focus into the toolbar, focus recently focused toolbar button
- Added more color functions to class `ColorFunctions` for easy use in
applications: `lighten()`, `darken()`, `saturate()`, `desaturate()`, `spin()`,
`tint()`, `shade()` and `luma()`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Insets;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
Expand All @@ -26,6 +28,7 @@
import javax.swing.AbstractButton;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
Expand All @@ -52,6 +55,7 @@
* <!-- FlatToolBarUI -->
*
* @uiDefault ToolBar.focusableButtons boolean
* @uiDefault ToolBar.arrowKeysOnlyNavigation boolean
* @uiDefault ToolBar.floatable boolean
*
* <!-- FlatToolBarBorder -->
Expand All @@ -65,13 +69,14 @@ public class FlatToolBarUI
extends BasicToolBarUI
implements StyleableUI
{
/** @since 1.4 */
@Styleable protected boolean focusableButtons;
/** @since 1.4 */ @Styleable protected boolean focusableButtons;
/** @since 2 */ @Styleable protected boolean arrowKeysOnlyNavigation;

// for FlatToolBarBorder
@Styleable protected Insets borderMargins;
@Styleable protected Color gripColor;

private FocusTraversalPolicy focusTraversalPolicy;
private Boolean oldFloatable;
private Map<String, Object> oldStyleValues;

Expand All @@ -83,6 +88,8 @@ public static ComponentUI createUI( JComponent c ) {
public void installUI( JComponent c ) {
super.installUI( c );

installFocusTraversalPolicy();

installStyle();

// disable focusable state of buttons (when switching from another Laf)
Expand All @@ -100,6 +107,8 @@ public void uninstallUI( JComponent c ) {
if( !focusableButtons )
setButtonsFocusable( true );

uninstallFocusTraversalPolicy();

oldStyleValues = null;
}

Expand All @@ -108,6 +117,7 @@ protected void installDefaults() {
super.installDefaults();

focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
arrowKeysOnlyNavigation = UIManager.getBoolean( "ToolBar.arrowKeysOnlyNavigation" );

// floatable
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
Expand Down Expand Up @@ -165,11 +175,18 @@ protected void installStyle() {
/** @since 2 */
protected void applyStyle( Object style ) {
boolean oldFocusableButtons = focusableButtons;
boolean oldArrowKeysOnlyNavigation = arrowKeysOnlyNavigation;

oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

if( focusableButtons != oldFocusableButtons )
setButtonsFocusable( focusableButtons );
if( arrowKeysOnlyNavigation != oldArrowKeysOnlyNavigation || focusableButtons != oldFocusableButtons ) {
if( arrowKeysOnlyNavigation )
installFocusTraversalPolicy();
else
uninstallFocusTraversalPolicy();
}
}

/** @since 2 */
Expand All @@ -194,6 +211,32 @@ private void setButtonFocusable( Component c, boolean focusable ) {
c.setFocusable( focusable );
}

/** @since 2 */
protected void installFocusTraversalPolicy() {
if( !arrowKeysOnlyNavigation || !focusableButtons || toolBar.getFocusTraversalPolicy() != null )
return;

focusTraversalPolicy = createFocusTraversalPolicy();
if( focusTraversalPolicy != null ) {
toolBar.setFocusTraversalPolicy( focusTraversalPolicy );
toolBar.setFocusTraversalPolicyProvider( true );
}
}

/** @since 2 */
protected void uninstallFocusTraversalPolicy() {
if( focusTraversalPolicy != null && toolBar.getFocusTraversalPolicy() == focusTraversalPolicy ) {
toolBar.setFocusTraversalPolicy( null );
toolBar.setFocusTraversalPolicyProvider( false );
}
focusTraversalPolicy = null;
}

/** @since 2 */
protected FocusTraversalPolicy createFocusTraversalPolicy() {
return new FlatToolBarFocusTraversalPolicy();
}

/**
* Does the same as super.navigateFocusedComp() with the exception that components
* with empty input map (e.g. JLabel) are skipped.
Expand Down Expand Up @@ -262,4 +305,51 @@ public void setOrientation( int orientation ) {

super.setOrientation( orientation );
}

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

/**
* Focus traversal policy used for toolbar to modify traversal behaviour:
* <ul>
* <li>Tab-key moves focus out of toolbar.</li>
* <li>If moving focus into the toolbar, focus recently focused toolbar button.</li>
* </ul>
*
* @since 2
*/
protected class FlatToolBarFocusTraversalPolicy
extends LayoutFocusTraversalPolicy
{
@Override
public Component getComponentAfter( Container aContainer, Component aComponent ) {
// move focus out of toolbar
return null;
}

@Override
public Component getComponentBefore( Container aContainer, Component aComponent ) {
// move focus out of toolbar
return null;
}

@Override
public Component getFirstComponent( Container aContainer ) {
return getRecentComponent( aContainer, true );
}

@Override
public Component getLastComponent( Container aContainer ) {
return getRecentComponent( aContainer, false );
}

private Component getRecentComponent( Container aContainer, boolean first ) {
// if moving focus into the toolbar, focus recently focused toolbar button
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() )
return toolBar.getComponent( focusedCompIndex );

return first
? super.getFirstComponent( aContainer )
: super.getLastComponent( aContainer );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -760,8 +760,9 @@ ToggleButton.tab.focusBackground = $TabbedPane.focusColor
ToolBar.border = com.formdev.flatlaf.ui.FlatToolBarBorder
ToolBar.borderMargins = 2,2,2,2
ToolBar.isRollover = true
ToolBar.floatable = false
ToolBar.focusableButtons = false
ToolBar.arrowKeysOnlyNavigation = true
ToolBar.floatable = false
ToolBar.gripColor = @icon
ToolBar.dockingBackground = darken($ToolBar.background,5%)
ToolBar.dockingForeground = $Component.borderColor
Expand Down
1 change: 1 addition & 0 deletions flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,7 @@ ToggleButtonUI com.formdev.flatlaf.ui.FlatToggleButtonUI

#---- ToolBar ----

ToolBar.arrowKeysOnlyNavigation true
ToolBar.background #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI]
ToolBar.border [lazy] 2,2,2,2 false com.formdev.flatlaf.ui.FlatToolBarBorder [UI]
ToolBar.borderMargins 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,7 @@ ToggleButtonUI com.formdev.flatlaf.ui.FlatToggleButtonUI

#---- ToolBar ----

ToolBar.arrowKeysOnlyNavigation true
ToolBar.background #f2f2f2 HSL 0 0 95 javax.swing.plaf.ColorUIResource [UI]
ToolBar.border [lazy] 2,2,2,2 false com.formdev.flatlaf.ui.FlatToolBarBorder [UI]
ToolBar.borderMargins 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
Expand Down
1 change: 1 addition & 0 deletions flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,7 @@ ToggleButtonUI com.formdev.flatlaf.ui.FlatToggleButtonUI

#---- ToolBar ----

ToolBar.arrowKeysOnlyNavigation true
ToolBar.background #ccffcc HSL 120 100 90 javax.swing.plaf.ColorUIResource [UI]
ToolBar.border [lazy] 2,2,2,2 false com.formdev.flatlaf.ui.FlatToolBarBorder [UI]
ToolBar.borderMargins 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ ToggleButton.toolbar.pressedBackground
ToggleButton.toolbar.selectedBackground
ToggleButtonUI
ToolBar.ancestorInputMap
ToolBar.arrowKeysOnlyNavigation
ToolBar.background
ToolBar.border
ToolBar.borderMargins
Expand Down

0 comments on commit 69042e4

Please sign in to comment.