Browse Source

Add JToggleButtonList.

Respect border insets when calculating bounds for the togglebutton slider variant.
pull/187/head
weisj 5 years ago
parent
commit
8c5c8ddc97
  1. 64
      core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/CheckBoxListItem.java
  2. 158
      core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/JToggleButtonList.java
  3. 49
      core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/ToggleButtonListCellRenderer.java
  4. 43
      core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/DarkToggleButtonBorder.java
  5. 27
      core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/DarkToggleButtonUI.java
  6. 4
      core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/radiobutton/DarkRadioButtonUI.java
  7. 2
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/toggleButton.properties
  8. 66
      core/src/test/java/ui/list/ToggleButtonListDemo.java
  9. 2
      property-loader/src/main/java/com/github/weisj/darklaf/icons/StateIcon.java
  10. 1
      utils/src/main/java/com/github/weisj/darklaf/util/PropertyKey.java

64
core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/CheckBoxListItem.java

@ -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.components.togglebuttonlist;
import javax.swing.*;
import com.github.weisj.darklaf.ui.togglebutton.DarkToggleButtonUI;
/**
* Each item in the CheckBxoList will be an instance of this class
*
* @author Naveed Quadri
*/
public class CheckBoxListItem extends JCheckBox {
private Object value = null;
public CheckBoxListItem(final Object itemValue, final boolean selected) {
super("", selected);
setValue(itemValue);
putClientProperty(DarkToggleButtonUI.KEY_IS_TABLE_EDITOR, true);
}
public Object getValue() {
return value;
}
/**
* The value of the JCheckbox label
*
* @param value the new value.
*/
public void setValue(final Object value) {
this.value = value;
setText(value == null ? "" : "" + value);
}
@Override
public String toString() {
return value.toString();
}
}

158
core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/JToggleButtonList.java

@ -0,0 +1,158 @@
/*
* 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.togglebuttonlist;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class JToggleButtonList extends JList<JToggleButton> {
public JToggleButtonList() {
super.setModel(new DefaultListModel<>());
super.setCellRenderer(new ToggleButtonListCellRenderer());
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
int index = locationToIndex(e.getPoint());
Rectangle bounds = getCellBounds(index, index);
if (index != -1) {
JToggleButton toggleButton = getModel().getElementAt(index);
// check if the click is on the togglebutton.
Point p = e.getPoint();
boolean inside = toggleButton.contains(p.x - bounds.x, p.y - bounds.y);
if (e.getClickCount() >= 2 || inside) {
toggleButton.setSelected(!toggleButton.isSelected());
fireSelectionValueChanged(index, index, inside);
}
repaint();
}
}
});
InputMap map = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(KeyStroke.getKeyStroke("released SPACE"), "toggle_togglebutton");
getActionMap().put("toggle_togglebutton", new AbstractAction("toggle_togglebutton") {
@Override
public void actionPerformed(final ActionEvent e) {
int leadIndex = getSelectionModel().getLeadSelectionIndex();
if (leadIndex >= 0) setSelected(leadIndex, !JToggleButtonList.this.isSelected(leadIndex));
}
});
super.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public void addToggleButton(final String text) {
addToggleButton(text, false);
}
public void addToggleButton(final String text, final boolean selected) {
addToggleButton(getModel().getSize(), text, selected);
}
public void addToggleButton(final int index, final String text) {
addToggleButton(index, text, false);
}
public void addToggleButton(final int index, final String text, final boolean selected) {
addToggleButton(index, new CheckBoxListItem(text, selected));
}
public void addToggleButton(final JToggleButton item) {
addToggleButton(getModel().getSize(), item);
}
public void addToggleButton(final int index, final JToggleButton item) {
gettogglebuttonModel().add(index, item);
}
public boolean isSelected(final int index) {
return gettogglebuttonModel().get(index).isSelected();
}
public void setSelected(final int index, final boolean selected) {
gettogglebuttonModel().get(index).setSelected(selected);
repaint(getCellBounds(index, index));
}
private DefaultListModel<JToggleButton> gettogglebuttonModel() {
return ((DefaultListModel<JToggleButton>) getModel());
}
/**
* Gets all the indices that are checked.
*
* @return Checked Indices
*/
public int[] getCheckedIndices() {
List<Integer> list = new ArrayList<>();
ListModel<JToggleButton> dlm = getModel();
for (int i = 0; i < dlm.getSize(); ++i) {
JToggleButton togglebutton = getModel().getElementAt(i);
if (togglebutton.isSelected()) {
list.add(i);
}
}
return list.stream().mapToInt(Integer::intValue).toArray();
}
/**
* Gets Checked Items
*
* @return Checked Items
*/
public List<JToggleButton> getCheckedItems() {
ArrayList<JToggleButton> list = new ArrayList<>();
ListModel<JToggleButton> dlm = getModel();
for (int i = 0; i < dlm.getSize(); ++i) {
JToggleButton togglebutton = dlm.getElementAt(i);
if (togglebutton.isSelected()) {
list.add(togglebutton);
}
}
return list;
}
@Override
public void setModel(final ListModel<JToggleButton> model) {}
@Override
public void setSelectionMode(final int selectionMode) {}
@Override
public void setSelectionModel(final ListSelectionModel selectionModel) {}
@Override
public void setCellRenderer(final ListCellRenderer<? super JToggleButton> cellRenderer) {}
}

49
core/src/main/java/com/github/weisj/darklaf/components/togglebuttonlist/ToggleButtonListCellRenderer.java

@ -0,0 +1,49 @@
/*
* 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.togglebuttonlist;
import java.awt.*;
import javax.swing.*;
public class ToggleButtonListCellRenderer implements ListCellRenderer<JToggleButton> {
@Override
public Component getListCellRendererComponent(final JList<? extends JToggleButton> list,
final JToggleButton value, final int index,
final boolean isSelected, final boolean cellHasFocus) {
value.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
value.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
value.setEnabled(list.isEnabled());
value.setFont(list.getFont());
value.setFocusPainted(cellHasFocus);
value.setBorderPainted(true);
value.setBorder(isSelected
? UIManager.getBorder("List.focusCellHighlightBorder")
: UIManager.getBorder("List.cellNoFocusBorder"));
return value;
}
}

43
core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/DarkToggleButtonBorder.java

@ -0,0 +1,43 @@
/*
* 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 java.awt.*;
import javax.swing.*;
import com.github.weisj.darklaf.ui.button.DarkButtonBorder;
public class DarkToggleButtonBorder extends DarkButtonBorder {
@Override
public Insets getBorderInsets(final Component c) {
if (c instanceof JToggleButton && ToggleButtonConstants.isSlider((JComponent) c)) {
int borderSize = getBorderSize();
return new Insets(borderSize, borderSize, borderSize, borderSize);
}
return super.getBorderInsets(c);
}
}

27
core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/DarkToggleButtonUI.java

@ -87,7 +87,7 @@ public class DarkToggleButtonUI extends DarkButtonUI implements ToggleButtonCons
if (ToggleButtonConstants.isSlider(c)) {
GraphicsContext config = GraphicsUtil.setupStrokePainting(g);
AbstractButton b = (AbstractButton) c;
String text = layoutSlider(b, c, SwingUtilities2.getFontMetrics(b, g), b.getWidth(), b.getHeight());
String text = layoutSlider(b, SwingUtilities2.getFontMetrics(b, g), b.getWidth(), b.getHeight());
paintSlider((Graphics2D) g, b);
paintIcon(g, b, c);
config.restoreClip();
@ -190,22 +190,27 @@ public class DarkToggleButtonUI extends DarkButtonUI implements ToggleButtonCons
}
protected Rectangle getSliderBounds(final JComponent c) {
int x = borderSize;
int y = (c.getHeight() - sliderSize.height) / 2;
Insets ins = c.getInsets();
int x = ins.left;
int height = c.getHeight() - ins.bottom - ins.top;
int y = ins.top + (height - sliderSize.height) / 2;
rect.x = x;
rect.y = y;
rect.width = sliderSize.width;
rect.height = sliderSize.height;
if (!c.getComponentOrientation().isLeftToRight()) {
rect.x = c.getWidth() - rect.x - rect.width;
rect.x = c.getWidth() - ins.right - rect.x - rect.width;
}
return rect;
}
private String layoutSlider(final AbstractButton b, final JComponent c,
final FontMetrics fm, final int width, final int height) {
private String layoutSlider(final AbstractButton b, final FontMetrics fm, final int width, final int height) {
Insets i = b.getInsets();
Rectangle bounds = getSliderBounds(c);
Rectangle bounds = getSliderBounds(b);
int arc = Math.min(bounds.width, bounds.height);
hitArea.setRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, arc, arc);
viewRect.x = bounds.x + bounds.width + 2 * borderSize;
viewRect.width = width - (i.right + viewRect.x);
viewRect.y = i.top;
@ -240,10 +245,10 @@ public class DarkToggleButtonUI extends DarkButtonUI implements ToggleButtonCons
@Override
public boolean contains(final JComponent c, final int x, final int y) {
if (!ToggleButtonConstants.isSlider(c)) return super.contains(c, x, y);
if (!(x >= 0 && x <= c.getWidth() && y >= 0 && y <= c.getHeight())) return false;
Rectangle bounds = getSliderBounds(c);
int arc = Math.min(bounds.width, bounds.height);
hitArea.setRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, arc, arc);
if ((hitArea.isEmpty()) && c instanceof JToggleButton) {
JToggleButton b = (JToggleButton) c;
layoutSlider(b, b.getFontMetrics(layoutDelegate.getFont()), b.getWidth(), b.getHeight());
}
return hitArea.contains(x, y);
}
}

4
core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/radiobutton/DarkRadioButtonUI.java

@ -217,7 +217,7 @@ public class DarkRadioButtonUI extends MetalRadioButtonUI implements PropertyCha
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
viewRect, iconRect, textRect, b.getIconTextGap());
iconRect.y += iconBaselineOffset;
if (ToggleButtonConstants.isTreeOrTableCellEditor(b)) {
if (ToggleButtonConstants.isInCell(b)) {
hitArea = calculateHitArea();
} else {
int x = Math.min(iconRect.x, textRect.x);
@ -261,6 +261,8 @@ public class DarkRadioButtonUI extends MetalRadioButtonUI implements PropertyCha
} else {
iconBaselineOffset = UIManager.getInt(getPropertyPrefix() + "iconBaselineOffset");
}
} else if (PropertyKey.BORDER.equals(key)) {
hitArea.setFrame(0, 0, 0, 0);
}
}
}

2
core/src/main/resources/com/github/weisj/darklaf/properties/ui/toggleButton.properties

@ -25,7 +25,7 @@
# suppress inspection "UnusedProperty" for whole file
#
ToggleButtonUI = com.github.weisj.darklaf.ui.togglebutton.DarkToggleButtonUI
ToggleButton.border = com.github.weisj.darklaf.ui.button.DarkButtonBorder
ToggleButton.border = com.github.weisj.darklaf.ui.togglebutton.DarkToggleButtonBorder
ToggleButton.sliderBorderColor = %widgetBorder
ToggleButton.disabledSliderBorderColor = %widgetBorderInactive
ToggleButton.focusedSliderBorderColor = %glowFocusLine

66
core/src/test/java/ui/list/ToggleButtonListDemo.java

@ -0,0 +1,66 @@
/*
* 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.list;
import java.awt.*;
import javax.swing.*;
import ui.ComponentDemo;
import ui.DemoPanel;
import com.github.weisj.darklaf.components.OverlayScrollPane;
import com.github.weisj.darklaf.components.togglebuttonlist.JToggleButtonList;
import com.github.weisj.darklaf.ui.togglebutton.DarkToggleButtonUI;
import com.github.weisj.darklaf.ui.togglebutton.ToggleButtonConstants;
public class ToggleButtonListDemo implements ComponentDemo {
public static void main(final String[] args) {
ComponentDemo.showDemo(new ToggleButtonListDemo());
}
@Override
public JComponent createComponent() {
JToggleButtonList list = new JToggleButtonList();
list.addToggleButton(new JCheckBox("CheckBox"));
list.addToggleButton(new JRadioButton("RadioButton"));
JToggleButton toggleButton = new JToggleButton("Slider ToggleButton");
toggleButton.putClientProperty(ToggleButtonConstants.KEY_VARIANT, DarkToggleButtonUI.VARIANT_SLIDER);
list.addToggleButton(toggleButton);
for (int i = 0; i < 20; i++) {
list.addToggleButton("Item " + i);
}
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(new OverlayScrollPane(list));
return new DemoPanel(panel, new BorderLayout(), 0);
}
@Override
public String getTitle() {
return "Checkbox List Demo";
}
}

2
property-loader/src/main/java/com/github/weisj/darklaf/icons/StateIcon.java

@ -79,7 +79,7 @@ public class StateIcon implements Icon {
AbstractButton b = (AbstractButton) c;
boolean selected = b.isSelected();
boolean enabled = b.isEnabled();
boolean hasFocus = b.hasFocus();
boolean hasFocus = b.isFocusPainted() && b.hasFocus();
Icon icn = selected ? enabled ? hasFocus ? selectedFocusedIcon : selectedIcon
: selectedDisabledIcon
: enabled ? hasFocus ? focusedIcon : icon

1
utils/src/main/java/com/github/weisj/darklaf/util/PropertyKey.java

@ -52,4 +52,5 @@ public class PropertyKey {
public static final String ROLLOVER = AbstractButton.ROLLOVER_ENABLED_CHANGED_PROPERTY;
public static final String LAF = "lookAndFeel";
public static final String GRAPHICS_CONFIGURATION = "graphicsConfiguration";
public static final String BORDER = "border";
}

Loading…
Cancel
Save