mirror of https://github.com/weisJ/darklaf.git
Browse Source
- opens a popup menu if no default action has been assigned. - displays a separate drop down button to access an action menu next to the button if a default actions has been set.pull/214/head
weisj
4 years ago
11 changed files with 763 additions and 49 deletions
@ -0,0 +1,120 @@ |
|||||||
|
/* |
||||||
|
* 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.components.button; |
||||||
|
|
||||||
|
import java.awt.event.ActionListener; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
public class JSplitButton extends JButton { |
||||||
|
|
||||||
|
public static final String KEY_ACTION_ADDED = "addedAction"; |
||||||
|
public static final String KEY_ACTION_REMOVED = "removedAction"; |
||||||
|
|
||||||
|
private JPopupMenu actionMenu; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a button with no set text or icon. |
||||||
|
*/ |
||||||
|
public JSplitButton() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a button with an icon. |
||||||
|
* |
||||||
|
* @param icon the Icon image to display on the button |
||||||
|
*/ |
||||||
|
public JSplitButton(final Icon icon) { |
||||||
|
super(icon); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a button with text. |
||||||
|
* |
||||||
|
* @param text the text of the button |
||||||
|
*/ |
||||||
|
public JSplitButton(final String text) { |
||||||
|
super(text); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a button where properties are taken from the <code>Action</code> supplied. |
||||||
|
* |
||||||
|
* @param a the <code>Action</code> used to specify the new button |
||||||
|
* |
||||||
|
* @since 1.3 |
||||||
|
*/ |
||||||
|
public JSplitButton(final Action a) { |
||||||
|
super(a); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a button with initial text and an icon. |
||||||
|
* |
||||||
|
* @param text the text of the button |
||||||
|
* @param icon the Icon image to display on the button |
||||||
|
*/ |
||||||
|
public JSplitButton(final String text, final Icon icon) { |
||||||
|
super(text, icon); |
||||||
|
} |
||||||
|
|
||||||
|
public int getActionCount() { |
||||||
|
return listenerList.getListenerCount(ActionListener.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getUIClassID() { |
||||||
|
return "SplitButtonUI"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addActionListener(final ActionListener l) { |
||||||
|
super.addActionListener(l); |
||||||
|
firePropertyChange(KEY_ACTION_ADDED, null, l); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void removeActionListener(final ActionListener l) { |
||||||
|
super.removeActionListener(l); |
||||||
|
firePropertyChange(KEY_ACTION_REMOVED, l, null); |
||||||
|
} |
||||||
|
|
||||||
|
public JPopupMenu getActionMenu() { |
||||||
|
if (actionMenu == null) { |
||||||
|
actionMenu = new JPopupMenu(); |
||||||
|
} |
||||||
|
return actionMenu; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
if (actionMenu != null) { |
||||||
|
SwingUtilities.updateComponentTreeUI(actionMenu); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setActionMenu(final JPopupMenu actionMenu) { |
||||||
|
this.actionMenu = actionMenu; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
/* |
||||||
|
* 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.splitbutton; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
import com.github.weisj.darklaf.components.button.JSplitButton; |
||||||
|
import com.github.weisj.darklaf.ui.button.ButtonConstants; |
||||||
|
import com.github.weisj.darklaf.ui.button.DarkButtonBorder; |
||||||
|
import com.github.weisj.darklaf.util.DarkUIUtil; |
||||||
|
|
||||||
|
public class DarkSplitButtonBorder extends DarkButtonBorder { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintBorderlessBorder(final Component c, final Graphics g, final int x, final int y, final int width, |
||||||
|
final int height) { |
||||||
|
if (showSplit(c)) { |
||||||
|
paintDivider(c, g, x, y, width, height); |
||||||
|
} |
||||||
|
super.paintBorderlessBorder(c, g, x, y, width, height); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintLineBorder(final Component c, final Graphics2D g2, final int arc, final boolean focus, |
||||||
|
final int bx, final int by, final int bw, final int bh) { |
||||||
|
if (showSplit(c)) { |
||||||
|
paintDivider(c, g2, bx, by, bw, bh); |
||||||
|
} |
||||||
|
super.paintLineBorder(c, g2, arc, focus, bx, by, bw, bh); |
||||||
|
} |
||||||
|
|
||||||
|
protected void paintDivider(final Component c, final Graphics g, final int x, final int y, final int width, |
||||||
|
final int height) { |
||||||
|
if (!(c instanceof JSplitButton)) return; |
||||||
|
Component arrowButton = ((JSplitButton) c).getComponent(0); |
||||||
|
if (arrowButton == null) return; |
||||||
|
boolean ltr = c.getComponentOrientation().isLeftToRight(); |
||||||
|
int splitPos = ltr ? arrowButton.getX() : arrowButton.getX() + arrowButton.getWidth() - 1; |
||||||
|
|
||||||
|
DarkSplitButtonUI ui = DarkUIUtil.getUIOfType(((JSplitButton) c).getUI(), DarkSplitButtonUI.class); |
||||||
|
if (ui != null && ui.getDrawOutline(c)) { |
||||||
|
boolean armed = ui.isArmedBorderless(ui.splitButton) |
||||||
|
|| (ui.useArrowButton() && ui.isArmedBorderless(ui.arrowButton)); |
||||||
|
g.setColor(ui.getBorderlessOutline(armed)); |
||||||
|
} else { |
||||||
|
g.setColor(getBorderColor(c, false)); |
||||||
|
} |
||||||
|
|
||||||
|
g.fillRect(splitPos, y, 1, height); |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean showSplit(final Component c) { |
||||||
|
boolean hasDefaultAction = c instanceof JSplitButton && ((JSplitButton) c).getActionCount() > 1; |
||||||
|
boolean borderless = ButtonConstants.isBorderlessVariant(c); |
||||||
|
if (!borderless) return hasDefaultAction; |
||||||
|
if (hasDefaultAction && ButtonConstants.isBorderlessVariant(c)) { |
||||||
|
DarkSplitButtonUI ui = DarkUIUtil.getUIOfType(((JSplitButton) c).getUI(), DarkSplitButtonUI.class); |
||||||
|
return ui != null && ui.isRolloverBorderless((AbstractButton) c); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
/* |
||||||
|
* 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.splitbutton; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import java.beans.PropertyChangeEvent; |
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.event.ChangeEvent; |
||||||
|
import javax.swing.event.ChangeListener; |
||||||
|
|
||||||
|
import com.github.weisj.darklaf.components.button.JSplitButton; |
||||||
|
import com.github.weisj.darklaf.ui.WidgetPopupHelper; |
||||||
|
import com.github.weisj.darklaf.ui.button.ButtonConstants; |
||||||
|
|
||||||
|
public class DarkSplitButtonListener implements ActionListener, PropertyChangeListener, ChangeListener { |
||||||
|
|
||||||
|
|
||||||
|
private final DarkSplitButtonUI ui; |
||||||
|
|
||||||
|
public DarkSplitButtonListener(final DarkSplitButtonUI ui) { |
||||||
|
this.ui = ui; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionPerformed(final ActionEvent e) { |
||||||
|
if (e.getSource() == ui.splitButton && ui.useArrowButton()) return; |
||||||
|
JPopupMenu actionMenu = ui.splitButton.getActionMenu(); |
||||||
|
if (actionMenu.isVisible()) { |
||||||
|
actionMenu.setVisible(false); |
||||||
|
} else { |
||||||
|
boolean splitButton = e.getSource() == ui.splitButton; |
||||||
|
actionMenu.setPreferredSize(null); |
||||||
|
Dimension size = actionMenu.getPreferredSize(); |
||||||
|
Rectangle popupBounds = |
||||||
|
WidgetPopupHelper.getPopupBounds(ui.splitButton, actionMenu, size, splitButton, !splitButton); |
||||||
|
if (splitButton) { |
||||||
|
actionMenu.setPreferredSize(popupBounds.getSize()); |
||||||
|
} |
||||||
|
actionMenu.show(ui.splitButton, popupBounds.x, popupBounds.y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void propertyChange(final PropertyChangeEvent evt) { |
||||||
|
String key = evt.getPropertyName(); |
||||||
|
if (JSplitButton.KEY_ACTION_ADDED.equals(key) || JSplitButton.KEY_ACTION_REMOVED.equals(key)) { |
||||||
|
ui.updateDefaultAction(); |
||||||
|
ui.splitButton.doLayout(); |
||||||
|
ui.splitButton.repaint(); |
||||||
|
} else if (ButtonConstants.KEY_THIN.equals(key)) { |
||||||
|
ui.updateArrowMargin(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void stateChanged(final ChangeEvent e) { |
||||||
|
ui.splitButton.repaint(); |
||||||
|
if (!ui.splitButton.hasFocus() && ui.arrowButton.getModel().isPressed()) { |
||||||
|
ui.splitButton.requestFocusInWindow(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,305 @@ |
|||||||
|
/* |
||||||
|
* 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.splitbutton; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.plaf.ComponentUI; |
||||||
|
|
||||||
|
import com.github.weisj.darklaf.components.ArrowButton; |
||||||
|
import com.github.weisj.darklaf.components.button.JSplitButton; |
||||||
|
import com.github.weisj.darklaf.icons.ToggleIcon; |
||||||
|
import com.github.weisj.darklaf.ui.button.ButtonConstants; |
||||||
|
import com.github.weisj.darklaf.ui.button.DarkButtonUI; |
||||||
|
import com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI; |
||||||
|
import com.github.weisj.darklaf.util.PropertyUtil; |
||||||
|
|
||||||
|
public class DarkSplitButtonUI extends DarkButtonUI { |
||||||
|
|
||||||
|
protected JSplitButton splitButton; |
||||||
|
protected AbstractButton arrowButton; |
||||||
|
private DarkSplitButtonListener arrowButtonListener; |
||||||
|
private Icon overlayIcon; |
||||||
|
private Icon overlayDisabledIcon; |
||||||
|
|
||||||
|
private ToggleIcon arrowToggleIcon; |
||||||
|
private ToggleIcon arrowDisabledToggleIcon; |
||||||
|
|
||||||
|
private Insets arrowInsets; |
||||||
|
private Insets arrowInsetsThin; |
||||||
|
private final Insets arrowButtonMargin = new Insets(0, 0, 0, 0); |
||||||
|
|
||||||
|
public static ComponentUI createUI(final JComponent c) { |
||||||
|
return new DarkSplitButtonUI(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void installUI(final JComponent c) { |
||||||
|
splitButton = (JSplitButton) c; |
||||||
|
super.installUI(c); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void uninstallUI(final JComponent c) { |
||||||
|
super.uninstallUI(c); |
||||||
|
splitButton = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void installDefaults(final AbstractButton b) { |
||||||
|
super.installDefaults(b); |
||||||
|
overlayIcon = UIManager.getIcon("SplitButton.overlayIcon"); |
||||||
|
overlayDisabledIcon = UIManager.getIcon("SplitButton.overlayDisabledIcon"); |
||||||
|
arrowInsets = UIManager.getInsets("SplitButton.arrowInsets"); |
||||||
|
arrowInsetsThin = UIManager.getInsets("SplitButton.arrowThinInsets"); |
||||||
|
Icon arrowIcon = UIManager.getIcon("SplitButton.arrowIcon"); |
||||||
|
Icon arrowIconDisabled = UIManager.getIcon("SplitButton.arrowIconDisabled"); |
||||||
|
Icon arrowIconThin = UIManager.getIcon("SplitButton.arrowThinIcon"); |
||||||
|
Icon arrowIconThinDisabled = UIManager.getIcon("SplitButton.arrowThinIconDisabled"); |
||||||
|
|
||||||
|
arrowToggleIcon = new ToggleIcon(arrowIcon, arrowIconThin); |
||||||
|
arrowDisabledToggleIcon = new ToggleIcon(arrowIconDisabled, arrowIconThinDisabled); |
||||||
|
|
||||||
|
PropertyUtil.installBorder(splitButton, new DarkSplitButtonBorder()); |
||||||
|
arrowButton = createArrowButton(); |
||||||
|
configureArrowButton(arrowButton); |
||||||
|
splitButton.add(arrowButton); |
||||||
|
updateArrowMargin(); |
||||||
|
updateDefaultAction(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void configureArrowButton(final AbstractButton button) { |
||||||
|
button.setRequestFocusEnabled(false); |
||||||
|
button.setInheritsPopupMenu(true); |
||||||
|
button.resetKeyboardActions(); |
||||||
|
button.setEnabled(splitButton.isEnabled()); |
||||||
|
button.putClientProperty(DarkPopupMenuUI.KEY_CONSUME_EVENT_ON_CLOSE, true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void installListeners(final AbstractButton b) { |
||||||
|
super.installListeners(b); |
||||||
|
arrowButtonListener = createArrowButtonListener(); |
||||||
|
arrowButton.addActionListener(arrowButtonListener); |
||||||
|
splitButton.addActionListener(arrowButtonListener); |
||||||
|
arrowButton.getModel().addChangeListener(arrowButtonListener); |
||||||
|
splitButton.addPropertyChangeListener(arrowButtonListener); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void uninstallListeners(final AbstractButton b) { |
||||||
|
super.uninstallListeners(b); |
||||||
|
arrowButton.removeActionListener(arrowButtonListener); |
||||||
|
splitButton.removeActionListener(arrowButtonListener); |
||||||
|
arrowButton.getModel().removeActionListener(arrowButtonListener); |
||||||
|
splitButton.removePropertyChangeListener(arrowButtonListener); |
||||||
|
arrowButtonListener = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void uninstallDefaults(final AbstractButton b) { |
||||||
|
super.uninstallDefaults(b); |
||||||
|
splitButton.remove(arrowButton); |
||||||
|
arrowButton = null; |
||||||
|
} |
||||||
|
|
||||||
|
protected void updateArrowMargin() { |
||||||
|
if (ButtonConstants.isThin(splitButton)) { |
||||||
|
arrowButtonMargin.set(arrowInsetsThin.top, arrowInsetsThin.left, arrowInsetsThin.bottom, |
||||||
|
arrowInsetsThin.right); |
||||||
|
arrowToggleIcon.setChooseAlternativeIcon(true); |
||||||
|
} else { |
||||||
|
arrowButtonMargin.set(arrowInsets.top, arrowInsets.left, arrowInsets.bottom, arrowInsets.right); |
||||||
|
arrowToggleIcon.setChooseAlternativeIcon(false); |
||||||
|
} |
||||||
|
splitButton.doLayout(); |
||||||
|
} |
||||||
|
|
||||||
|
protected DarkSplitButtonListener createArrowButtonListener() { |
||||||
|
return new DarkSplitButtonListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
protected AbstractButton createArrowButton() { |
||||||
|
AbstractButton b = ArrowButton.createUpDownArrow(splitButton, arrowToggleIcon, arrowDisabledToggleIcon, |
||||||
|
SwingConstants.SOUTH, true, true, arrowButtonMargin); |
||||||
|
b.setRolloverEnabled(true); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Dimension getPreferredSize(final JComponent c) { |
||||||
|
Dimension dim = super.getPreferredSize(c); |
||||||
|
if (useArrowButton()) { |
||||||
|
Dimension arrowSize = arrowButton.getPreferredSize(); |
||||||
|
dim.width += arrowSize.width; |
||||||
|
dim.height = Math.max(dim.height, arrowSize.height); |
||||||
|
} |
||||||
|
return dim; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected LayoutManager createLayout() { |
||||||
|
return new DarkSplitButtonLayout(); |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean useArrowButton() { |
||||||
|
return arrowButton != null && splitButton.getActionCount() > 1; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintIcon(final Graphics g, final AbstractButton b, final JComponent c) { |
||||||
|
super.paintIcon(g, b, c); |
||||||
|
if (b.getIcon() != null && !useArrowButton()) { |
||||||
|
Icon overlay = b.isEnabled() ? overlayIcon : overlayDisabledIcon; |
||||||
|
overlay.paintIcon(c, g, iconRect.x + iconRect.width - overlay.getIconWidth(), |
||||||
|
iconRect.y + iconRect.height - overlay.getIconHeight()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isRolloverBorderless(final AbstractButton b) { |
||||||
|
return super.isRolloverBorderless(b) || (useArrowButton() && arrowButton.getModel().isRollover()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintDarklafBorderBgImpl(final AbstractButton c, final Graphics2D g, final boolean showShadow, |
||||||
|
final int shadow, final int effectiveArc, final Rectangle bgRect) { |
||||||
|
super.paintDarklafBorderBgImpl(c, g, showShadow, shadow, effectiveArc, bgRect); |
||||||
|
if (useArrowButton()) { |
||||||
|
boolean isDefault = splitButton.isDefaultButton(); |
||||||
|
boolean enabled = splitButton.isEnabled(); |
||||||
|
boolean rollover = c.isRolloverEnabled() && arrowButton.getModel().isRollover(); |
||||||
|
boolean clicked = arrowButton.getModel().isArmed(); |
||||||
|
g.setColor(getBackgroundColor(splitButton, isDefault, rollover, clicked, enabled)); |
||||||
|
Shape clip = g.getClip(); |
||||||
|
boolean ltr = c.getComponentOrientation().isLeftToRight(); |
||||||
|
if (ltr) { |
||||||
|
g.clipRect(arrowButton.getX(), 0, button.getWidth(), button.getHeight()); |
||||||
|
} else { |
||||||
|
g.clipRect(0, 0, arrowButton.getX() + arrowButton.getWidth(), button.getHeight()); |
||||||
|
} |
||||||
|
paintBackgroundRect(g, effectiveArc, bgRect); |
||||||
|
g.setClip(clip); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void setArmedClip(final AbstractButton c, final Graphics g) { |
||||||
|
boolean ltr = c.getComponentOrientation().isLeftToRight(); |
||||||
|
boolean arrowArmed = arrowButton.getModel().isRollover(); |
||||||
|
if (ltr) { |
||||||
|
if (arrowArmed) { |
||||||
|
g.clipRect(arrowButton.getX(), 0, splitButton.getWidth(), splitButton.getHeight()); |
||||||
|
} else { |
||||||
|
g.clipRect(0, 0, arrowButton.getX(), splitButton.getHeight()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (arrowArmed) { |
||||||
|
g.clipRect(0, 0, arrowButton.getX() + arrowButton.getWidth(), splitButton.getHeight()); |
||||||
|
} else { |
||||||
|
g.clipRect(arrowButton.getX() + arrowButton.getWidth(), 0, splitButton.getWidth(), |
||||||
|
splitButton.getHeight()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintBorderlessBackgroundImpl(final AbstractButton b, final Graphics2D g, final int arc, final int x, |
||||||
|
final int y, final int w, final int h) { |
||||||
|
boolean splitArmed = splitButton.getModel().isArmed(); |
||||||
|
boolean arrowArmed = arrowButton.getModel().isArmed(); |
||||||
|
Shape clip = g.getClip(); |
||||||
|
if (splitArmed) { |
||||||
|
super.paintBorderlessBackgroundImpl(arrowButton, g, arc, x, y, w, h); |
||||||
|
setArmedClip(splitButton, g); |
||||||
|
super.paintBorderlessBackgroundImpl(splitButton, g, arc, x, y, w, h); |
||||||
|
} else if (arrowArmed) { |
||||||
|
super.paintBorderlessBackgroundImpl(splitButton, g, arc, x, y, w, h); |
||||||
|
setArmedClip(splitButton, g); |
||||||
|
super.paintBorderlessBackgroundImpl(arrowButton, g, arc, x, y, w, h); |
||||||
|
} else { |
||||||
|
super.paintBorderlessBackgroundImpl(b, g, arc, x, y, w, h); |
||||||
|
} |
||||||
|
g.setClip(clip); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintBorderlessRectangularBackgroundIml(final AbstractButton b, final Graphics2D g, final int x, |
||||||
|
final int y, final int w, final int h) { |
||||||
|
boolean splitArmed = splitButton.getModel().isArmed(); |
||||||
|
boolean arrowArmed = splitButton.getModel().isArmed(); |
||||||
|
Shape clip = g.getClip(); |
||||||
|
if (splitArmed) { |
||||||
|
super.paintBorderlessRectangularBackgroundIml(arrowButton, g, x, y, w, h); |
||||||
|
setArmedClip(splitButton, g); |
||||||
|
super.paintBorderlessRectangularBackgroundIml(splitButton, g, x, y, w, h); |
||||||
|
} else if (arrowArmed) { |
||||||
|
super.paintBorderlessRectangularBackgroundIml(splitButton, g, x, y, w, h); |
||||||
|
setArmedClip(splitButton, g); |
||||||
|
super.paintBorderlessRectangularBackgroundIml(arrowButton, g, x, y, w, h); |
||||||
|
} else { |
||||||
|
super.paintBorderlessRectangularBackgroundIml(b, g, x, y, w, h); |
||||||
|
} |
||||||
|
g.setClip(clip); |
||||||
|
} |
||||||
|
|
||||||
|
public void updateDefaultAction() { |
||||||
|
arrowButton.setVisible(useArrowButton()); |
||||||
|
splitButton.putClientProperty(DarkPopupMenuUI.KEY_CONSUME_EVENT_ON_CLOSE, !useArrowButton()); |
||||||
|
} |
||||||
|
|
||||||
|
protected class DarkSplitButtonLayout extends DarkButtonLayout { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void layoutContainer(final Container parent) { |
||||||
|
super.layoutContainer(parent); |
||||||
|
if (useArrowButton()) { |
||||||
|
Insets ins = parent.getInsets(); |
||||||
|
Dimension arrowSize = arrowButton.getPreferredSize(); |
||||||
|
boolean ltr = splitButton.getComponentOrientation().isLeftToRight(); |
||||||
|
if (ltr) { |
||||||
|
arrowButton.setBounds(parent.getWidth() - ins.right - arrowSize.width, 0, |
||||||
|
arrowSize.width + ins.right, parent.getHeight()); |
||||||
|
arrowButton.setMargin(new Insets(ins.top, 0, ins.bottom, ins.right)); |
||||||
|
} else { |
||||||
|
arrowButton.setBounds(ins.left, ins.top, arrowSize.width, |
||||||
|
parent.getHeight() - ins.top - ins.bottom); |
||||||
|
arrowButton.setMargin(new Insets(ins.top, ins.left, ins.bottom, 0)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void prepareContentRects(final AbstractButton b, final int width, final int height) { |
||||||
|
super.prepareContentRects(b, width, height); |
||||||
|
if (useArrowButton()) { |
||||||
|
Dimension arrowSize = arrowButton.getPreferredSize(); |
||||||
|
boolean ltr = splitButton.getComponentOrientation().isLeftToRight(); |
||||||
|
viewRect.width -= arrowSize.width; |
||||||
|
if (!ltr) { |
||||||
|
viewRect.x += arrowSize.width; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 392 B |
After Width: | Height: | Size: 408 B |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* 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 ui.button; |
||||||
|
|
||||||
|
import java.awt.event.ActionListener; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
import ui.ComponentDemo; |
||||||
|
import ui.DemoResources; |
||||||
|
|
||||||
|
import com.github.weisj.darklaf.components.button.JSplitButton; |
||||||
|
|
||||||
|
public class SplitButtonDemo extends ButtonDemo { |
||||||
|
|
||||||
|
public static void main(final String[] args) { |
||||||
|
ComponentDemo.showDemo(new SplitButtonDemo()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected JButton createButton() { |
||||||
|
Icon icon = DemoResources.FOLDER_ICON; |
||||||
|
JSplitButton button = new JSplitButton("Split Button", icon); |
||||||
|
JPopupMenu menu = button.getActionMenu(); |
||||||
|
for (int i = 0; i < 5; i++) { |
||||||
|
menu.add("Item " + i); |
||||||
|
} |
||||||
|
return button; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void addCheckBoxControls(final JPanel controlPanel, final JButton button) { |
||||||
|
super.addCheckBoxControls(controlPanel, button); |
||||||
|
controlPanel.add(new JCheckBox("Default action set") { |
||||||
|
private final ActionListener l = ee -> { |
||||||
|
}; |
||||||
|
|
||||||
|
{ |
||||||
|
addActionListener(e -> { |
||||||
|
if (isSelected()) { |
||||||
|
button.addActionListener(l); |
||||||
|
} else { |
||||||
|
button.removeActionListener(l); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getTitle() { |
||||||
|
return "Split Button Demo"; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue