mirror of https://github.com/weisJ/darklaf.git
weisj
5 years ago
6 changed files with 398 additions and 5 deletions
@ -0,0 +1,188 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2020 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all |
||||
* copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
* SOFTWARE. |
||||
*/ |
||||
package com.github.weisj.darklaf.ui.togglebutton; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.util.Enumeration; |
||||
import java.util.HashSet; |
||||
|
||||
public class ButtonGroupInfo { |
||||
protected JToggleButton activeButton; |
||||
|
||||
protected JToggleButton firstButton = null; |
||||
protected JToggleButton lastButton = null; |
||||
|
||||
protected JToggleButton previousButton = null; |
||||
protected JToggleButton nextButton = null; |
||||
|
||||
protected HashSet<JToggleButton> buttonsInGroup; |
||||
protected boolean sourceFound = false; |
||||
|
||||
public ButtonGroupInfo(final JToggleButton btn) { |
||||
activeButton = btn; |
||||
buttonsInGroup = new HashSet<>(); |
||||
} |
||||
|
||||
public static boolean isValidToggleButtonObject(final Object obj) { |
||||
return obj instanceof JToggleButton |
||||
&& ((JToggleButton) obj).isEnabled() |
||||
&& ((JToggleButton) obj).isVisible(); |
||||
} |
||||
|
||||
protected boolean containsInGroup(final JToggleButton button) { |
||||
return buttonsInGroup.contains(button); |
||||
} |
||||
|
||||
protected Component getFocusTransferBaseComponent(final boolean next) { |
||||
return firstButton; |
||||
} |
||||
|
||||
protected boolean getButtonGroupInfo() { |
||||
if (activeButton == null) { |
||||
return false; |
||||
} |
||||
|
||||
buttonsInGroup.clear(); |
||||
|
||||
// Get the button model from the source.
|
||||
ButtonModel model = activeButton.getModel(); |
||||
if (!(model instanceof DefaultButtonModel)) { |
||||
return false; |
||||
} |
||||
|
||||
// If the button model is DefaultButtonModel, and use it, otherwise return.
|
||||
DefaultButtonModel bm = (DefaultButtonModel) model; |
||||
|
||||
// get the ButtonGroup of the button from the button model
|
||||
ButtonGroup group = bm.getGroup(); |
||||
if (group == null) { |
||||
return false; |
||||
} |
||||
|
||||
// Get all the buttons in the group
|
||||
Enumeration<AbstractButton> e = group.getElements(); |
||||
if (e == null) { |
||||
return false; |
||||
} |
||||
|
||||
while (e.hasMoreElements()) { |
||||
AbstractButton curElement = e.nextElement(); |
||||
if (!isValidToggleButtonObject(curElement)) { |
||||
continue; |
||||
} |
||||
|
||||
buttonsInGroup.add((JToggleButton) curElement); |
||||
|
||||
// If firstBtn is not set yet, curElement is that first button
|
||||
if (firstButton == null) { |
||||
firstButton = (JToggleButton) curElement; |
||||
} |
||||
|
||||
if (activeButton == curElement) { |
||||
sourceFound = true; |
||||
} else if (!sourceFound) { |
||||
// The source has not been yet found and the current element
|
||||
// is the last previousBtn
|
||||
previousButton = (JToggleButton) curElement; |
||||
} else if (nextButton == null) { |
||||
// The source has been found and the current element
|
||||
// is the next valid button of the list
|
||||
nextButton = (JToggleButton) curElement; |
||||
} |
||||
|
||||
// Set new last "valid" JToggleButton of the list
|
||||
lastButton = (JToggleButton) curElement; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Find the new radio button that focus needs to be |
||||
* moved to in the group, select the button |
||||
* |
||||
* @param next, indicate if it's arrow up/left or down/right |
||||
*/ |
||||
protected void selectNewButton(final boolean next) { |
||||
if (!getButtonGroupInfo()) { |
||||
return; |
||||
} |
||||
|
||||
if (sourceFound) { |
||||
JToggleButton newSelectedButton; |
||||
if (next) { |
||||
// Select Next button. Cycle to the first button if the source.
|
||||
// button is the last of the group.
|
||||
newSelectedButton = (null == nextButton) ? firstButton : nextButton; |
||||
} else { |
||||
// Select previous button. Cycle to the last button if the source.
|
||||
// button is the first button of the group.
|
||||
newSelectedButton = (null == previousButton) ? lastButton : previousButton; |
||||
} |
||||
if (newSelectedButton != null && |
||||
(newSelectedButton != activeButton)) { |
||||
newSelectedButton.requestFocusInWindow(); |
||||
// newSelectedButton.setSelected(true);
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Find the button group the passed in JToggleButton belongs to, and |
||||
* move focus to next component of the last button in the group |
||||
* or previous component of first button |
||||
* |
||||
* @param next, indicate if jump to next component or previous |
||||
*/ |
||||
protected void jumpToNextComponent(final boolean next) { |
||||
if (!getButtonGroupInfo()) { |
||||
// In case the button does not belong to any group, it needs
|
||||
// to be treated as a component
|
||||
if (activeButton != null) { |
||||
lastButton = activeButton; |
||||
firstButton = activeButton; |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
// Update the component we will use as base to transfer
|
||||
// focus from
|
||||
JComponent compTransferFocusFrom = activeButton; |
||||
|
||||
// If next component in the parent window is not in
|
||||
// the button group, current active button will be
|
||||
// base, otherwise, the base will be first or last
|
||||
// button in the button group
|
||||
Component focusBase = getFocusTransferBaseComponent(next); |
||||
if (focusBase != null) { |
||||
if (next) { |
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(focusBase); |
||||
} else { |
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(focusBase); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,64 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2020 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all |
||||
* copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
* SOFTWARE. |
||||
*/ |
||||
package com.github.weisj.darklaf.ui.togglebutton; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.event.KeyEvent; |
||||
import java.awt.event.KeyListener; |
||||
import java.util.Set; |
||||
|
||||
public class DarkToggleButtonKeyHandler implements KeyListener { |
||||
|
||||
// This listener checks if the key event is a focus traversal key event
|
||||
// on a radio button, consume the event if so and move the focus
|
||||
// to next/previous component
|
||||
public void keyPressed(final KeyEvent e) { |
||||
AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); |
||||
if (stroke != null && e.getSource() instanceof JRadioButton) { |
||||
JRadioButton source = (JRadioButton) e.getSource(); |
||||
boolean next = isFocusTraversalKey(source, |
||||
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, |
||||
stroke); |
||||
if (next || isFocusTraversalKey(source, |
||||
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, |
||||
stroke)) { |
||||
e.consume(); |
||||
ButtonGroupInfo btnGroupInfo = new ButtonGroupInfo(source); |
||||
btnGroupInfo.jumpToNextComponent(next); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private boolean isFocusTraversalKey(final JComponent c, final int id, final AWTKeyStroke stroke) { |
||||
Set<AWTKeyStroke> keys = c.getFocusTraversalKeys(id); |
||||
return keys != null && keys.contains(stroke); |
||||
} |
||||
|
||||
public void keyReleased(final KeyEvent e) { |
||||
} |
||||
|
||||
public void keyTyped(final KeyEvent e) { |
||||
} |
||||
} |
@ -0,0 +1,92 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2020 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all |
||||
* copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
* SOFTWARE. |
||||
*/ |
||||
package com.github.weisj.darklaf.ui.togglebutton; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.event.ActionEvent; |
||||
|
||||
public class ToggleButtonFocusNavigationActions { |
||||
|
||||
public static void installActions(final AbstractButton button) { |
||||
if (button == null) return; |
||||
button.getActionMap().put("Previous", new SelectPreviousBtn()); |
||||
button.getActionMap().put("Next", new SelectNextBtn()); |
||||
|
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT). |
||||
put(KeyStroke.getKeyStroke("UP"), "Previous"); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT). |
||||
put(KeyStroke.getKeyStroke("DOWN"), "Next"); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT). |
||||
put(KeyStroke.getKeyStroke("LEFT"), "Previous"); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT). |
||||
put(KeyStroke.getKeyStroke("RIGHT"), "Next"); |
||||
} |
||||
|
||||
public static void uninstallActions(final AbstractButton button) { |
||||
if (button == null) return; |
||||
button.getActionMap().remove("Previous"); |
||||
button.getActionMap().remove("Next"); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) |
||||
.remove(KeyStroke.getKeyStroke("UP")); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) |
||||
.remove(KeyStroke.getKeyStroke("DOWN")); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) |
||||
.remove(KeyStroke.getKeyStroke("LEFT")); |
||||
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) |
||||
.remove(KeyStroke.getKeyStroke("RIGHT")); |
||||
} |
||||
|
||||
protected static void selectToggleButton(final ActionEvent event, final boolean next) { |
||||
// Get the source of the event.
|
||||
Object eventSrc = event.getSource(); |
||||
|
||||
// Check whether the source is JRadioButton, it so, whether it is visible
|
||||
if (!ButtonGroupInfo.isValidToggleButtonObject(eventSrc)) { |
||||
return; |
||||
} |
||||
|
||||
ButtonGroupInfo btnGroupInfo = new ButtonGroupInfo((JToggleButton) eventSrc); |
||||
btnGroupInfo.selectNewButton(next); |
||||
} |
||||
|
||||
public static class SelectPreviousBtn extends AbstractAction { |
||||
public SelectPreviousBtn() { |
||||
super("Previous"); |
||||
} |
||||
|
||||
public void actionPerformed(final ActionEvent e) { |
||||
selectToggleButton(e, false); |
||||
} |
||||
} |
||||
|
||||
public static class SelectNextBtn extends AbstractAction { |
||||
public SelectNextBtn() { |
||||
super("Next"); |
||||
} |
||||
|
||||
public void actionPerformed(final ActionEvent e) { |
||||
selectToggleButton(e, true); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue