Browse Source

Add option to add and edit entries in ThemeEditor.

pull/222/head
weisj 4 years ago
parent
commit
58d92a0020
  1. 51
      core/src/main/java/com/github/weisj/darklaf/layout/LayoutManagerAdapter.java
  2. 46
      core/src/test/java/theme/MapTableModel.java
  3. 188
      core/src/test/java/theme/ThemeEditor.java
  4. 15
      core/src/test/resources/icon/addEntry.svg
  5. 10
      core/src/test/resources/icon/word.svg

51
core/src/main/java/com/github/weisj/darklaf/layout/LayoutManagerAdapter.java

@ -0,0 +1,51 @@
/*
* 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.layout;
import java.awt.*;
public class LayoutManagerAdapter implements LayoutManager {
@Override
public void addLayoutComponent(final String name, final Component comp) {
}
@Override
public void removeLayoutComponent(final Component comp) {
}
@Override
public Dimension preferredLayoutSize(final Container parent) {
return null;
}
@Override
public Dimension minimumLayoutSize(final Container parent) {
return null;
}
@Override
public void layoutContainer(final Container parent) {
}
}

46
core/src/test/java/theme/MapTableModel.java

@ -22,15 +22,19 @@
package theme;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;
class MapTableModel extends DefaultTableModel {
private final LinkedHashMap<Object, Object> values;
private final boolean keyEditable;
MapTableModel(final LinkedHashMap<Object, Object> values) {
MapTableModel(final LinkedHashMap<Object, Object> values, final boolean keyEditable) {
this.values = values;
this.keyEditable = keyEditable;
}
@Override
@ -55,7 +59,7 @@ class MapTableModel extends DefaultTableModel {
@Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
return columnIndex == 1;
return columnIndex == 1 || keyEditable;
}
@Override
@ -67,13 +71,45 @@ class MapTableModel extends DefaultTableModel {
}
}
@Override
public void insertRow(final int row, final Vector rowData) {
values.put(rowData.get(0), rowData.get(1));
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
}
@Override
public void removeRow(final int row) {
values.remove(getKeyByIndex(row));
fireTableRowsDeleted(row, row);
}
@Override
public void addColumn(final Object columnName, final Vector columnData) {
throw new UnsupportedOperationException();
}
@Override
public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
if (columnIndex == 0) return;
values.put(getKeyByIndex(rowIndex), aValue);
if (columnIndex == 0) {
if (!keyEditable) return;
@SuppressWarnings("unchecked")
Map.Entry<Object, Object>[] entries =
(Map.Entry<Object, Object>[]) values.entrySet().toArray(new Map.Entry[0]);
for (int i = rowIndex; i < entries.length; i++) {
values.remove(entries[i].getKey());
}
values.put(aValue, entries[rowIndex].getValue());
for (int i = rowIndex + 1; i < entries.length; i++) {
values.remove(entries[i].getKey());
}
fireTableCellUpdated(rowIndex, columnIndex);
} else {
values.put(getKeyByIndex(rowIndex), aValue);
fireTableCellUpdated(rowIndex, columnIndex);
}
}
public String getKeyByIndex(final int index) {
return values.keySet().toArray(new String[0])[index];
return values.keySet().toArray(new Object[0])[index].toString();
}
}

188
core/src/test/java/theme/ThemeEditor.java

@ -27,8 +27,10 @@ import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import ui.ComponentDemo;
@ -37,15 +39,28 @@ import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.components.DefaultButton;
import com.github.weisj.darklaf.components.OverlayScrollPane;
import com.github.weisj.darklaf.components.border.DarkBorders;
import com.github.weisj.darklaf.components.button.JSplitButton;
import com.github.weisj.darklaf.graphics.GraphicsContext;
import com.github.weisj.darklaf.graphics.PaintUtil;
import com.github.weisj.darklaf.graphics.ThemedColor;
import com.github.weisj.darklaf.icons.DerivableIcon;
import com.github.weisj.darklaf.icons.IconLoader;
import com.github.weisj.darklaf.icons.OverlayIcon;
import com.github.weisj.darklaf.icons.TextIcon;
import com.github.weisj.darklaf.layout.LayoutManagerAdapter;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.theme.ThemeDelegate;
import com.github.weisj.darklaf.theme.info.AccentColorRule;
import com.github.weisj.darklaf.theme.info.ColorToneRule;
import com.github.weisj.darklaf.theme.info.ContrastRule;
import com.github.weisj.darklaf.theme.info.FontSizeRule;
import com.github.weisj.darklaf.ui.button.ButtonConstants;
import com.github.weisj.darklaf.ui.table.TableConstants;
import com.github.weisj.darklaf.ui.togglebutton.ToggleButtonConstants;
import com.github.weisj.darklaf.uiresource.DarkColorUIResource;
import com.github.weisj.darklaf.util.Alignment;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.FontUtil;
import defaults.UIManagerDefaults;
public class ThemeEditor extends JPanel {
@ -113,11 +128,11 @@ public class ThemeEditor extends JPanel {
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
tabbedPane.addTab("Theme defaults", createTable(themeDefaults));
tabbedPane.addTab("Icon defaults", createTable(iconDefaults));
tabbedPane.addTab("UI customs", createTable(uiDefaults));
tabbedPane.addTab("Global customs", createTable(globalDefaults));
tabbedPane.addTab("Platform customs", createTable(platformDefaults));
tabbedPane.addTab("Theme defaults", createTable(themeDefaults, false));
tabbedPane.addTab("Icon defaults", createTable(iconDefaults, false));
tabbedPane.addTab("UI customs", createTable(uiDefaults, true));
tabbedPane.addTab("Global customs", createTable(globalDefaults, true));
tabbedPane.addTab("Platform customs", createTable(platformDefaults, true));
tabbedPane.addTab("All Defaults (Read only)", new UIManagerDefaults().createComponent());
content.add(tabbedPane, BorderLayout.CENTER);
@ -233,15 +248,172 @@ public class ThemeEditor extends JPanel {
});
}
private JComponent createTable(final LinkedHashMap<Object, Object> valueMap) {
enum EntryType {
COLOR("Add Color", Color.BLACK, DarkUIUtil.ICON_LOADER.getIcon("menu/colorChooser.svg")),
INTEGER("Add Integer", 0, ((Supplier<Icon>) () -> {
Font font = FontUtil.createFont(Font.MONOSPACED, Font.BOLD, 13);
return new TextIcon("42", new ThemedColor("menuIconEnabled"), font, 16, 16);
}).get()),
BOOLEAN("Add Boolean", false, DarkUIUtil.ICON_LOADER.getIcon("control/checkboxSelectedFocused.svg", true)),
STRING("Add String", "", IconLoader.get().getIcon("icon/word.svg", true));
private final String s;
private final Object defaultValue;
private final Icon icon;
private int entryCount;
EntryType(final String s, final Object defaultValue, final Icon icon) {
this.s = s;
this.defaultValue = defaultValue;
this.icon = icon;
}
public String getText() {
return s;
}
@SuppressWarnings("unchecked")
public DerivableIcon<Icon> getIcon() {
return (DerivableIcon<Icon>) icon;
}
public void addElement(final JTable table) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.addRow(new Object[] {"<" + name() + "_" + (entryCount++) + ">", defaultValue});
}
}
private JComponent createTable(final LinkedHashMap<Object, Object> valueMap, final boolean keyEditable) {
JTable table = new JTable();
table.setModel(new MapTableModel(valueMap));
table.getTableHeader().setReorderingAllowed(false);
table.setShowHorizontalLines(false);
table.setModel(new MapTableModel(valueMap, keyEditable));
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.putClientProperty(TableConstants.KEY_CELL_VALUE_DETERMINES_EDITOR_CLASS, true);
OverlayScrollPane sp = new OverlayScrollPane(table);
JPanel buttonPanel = keyEditable ? createButtonPanel(table) : null;
OverlayScrollPane sp = new OverlayScrollPane(table) {
@Override
public void doLayout() {
super.doLayout();
if (!keyEditable) return;
Dimension prefSize = buttonPanel.getPreferredSize();
int pad = 10;
Component viewport = getScrollPane().getViewport();
Rectangle viewBounds = new Rectangle(0, 0, viewport.getWidth(), viewport.getHeight());
viewBounds = SwingUtilities.convertRectangle(viewport, viewBounds, this);
int x = viewBounds.x - pad - prefSize.width;
int columnEnd = table.getColumnModel().getColumn(0).getWidth();
if (getVerticalScrollBar() != null && getVerticalScrollBar().isVisible()) {
columnEnd = Math.min(columnEnd, viewBounds.width - getVerticalScrollBar().getWidth());
}
x += columnEnd;
buttonPanel.setBounds(x, viewBounds.y + pad, prefSize.width, prefSize.height);
buttonPanel.doLayout();
}
};
if (keyEditable) {
sp.add(buttonPanel, Integer.valueOf(JLayeredPane.MODAL_LAYER - 1));
}
sp.doLayout();
sp.getScrollPane().setBorder(DarkBorders.createLineBorder(0, 0, 1, 0));
return sp;
}
private JPanel createButtonPanel(final JTable table) {
AtomicReference<EntryType> lastSelection = new AtomicReference<>(EntryType.COLOR);
OverlayIcon overlayIcon =
new OverlayIcon(
DarkUIUtil.ICON_LOADER.getIcon("navigation/add.svg", true),
lastSelection.get().getIcon().derive(8, 8),
Alignment.SOUTH_EAST);
JSplitButton addButton = new JSplitButton(overlayIcon);
addButton.setFocusable(false);
addButton.setToolTipText(lastSelection.get().getText());
JPopupMenu menu = addButton.getActionMenu();
for (EntryType type : EntryType.values()) {
menu.add(new JMenuItem(type.getText(), type.getIcon())).addActionListener(e -> {
lastSelection.set(type);
addButton.setToolTipText(type.getText());
overlayIcon.setOverlay(type.getIcon().derive(8, 8));
addButton.repaint();
});
}
addButton.addActionListener(e -> lastSelection.get().addElement(table));
addButton.putClientProperty(ButtonConstants.KEY_VARIANT, ButtonConstants.VARIANT_BORDERLESS);
addButton.putClientProperty(ButtonConstants.KEY_SQUARE, true);
addButton.putClientProperty(ButtonConstants.KEY_THIN, true);
JButton deleteButton = new JButton();
deleteButton.setToolTipText("Remove selected entry");
deleteButton.setIcon(DarkUIUtil.ICON_LOADER.getIcon("menu/delete.svg"));
deleteButton.setDisabledIcon(DarkUIUtil.ICON_LOADER.getIcon("menu/deleteDisabled.svg"));
deleteButton.putClientProperty(ButtonConstants.KEY_VARIANT, ButtonConstants.VARIANT_BORDERLESS);
deleteButton.putClientProperty(ButtonConstants.KEY_SQUARE, true);
deleteButton.putClientProperty(ButtonConstants.KEY_THIN, true);
deleteButton.setEnabled(table.getSelectedRow() >= 0);
deleteButton.setFocusable(false);
deleteButton.addActionListener(e -> {
int row = table.getSelectedRow();
((DefaultTableModel) table.getModel()).removeRow(row);
table.clearSelection();
int newRow = row > 0 ? row - 1 : row;
if (newRow < table.getModel().getRowCount()) {
table.addRowSelectionInterval(newRow, newRow);
}
});
table.getSelectionModel().addListSelectionListener(e -> deleteButton.setEnabled(table.getSelectedRow() >= 0));
JPanel buttonPanel = new JPanel() {
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
GraphicsContext context = new GraphicsContext(g);
((Graphics2D) g).setComposite(PaintUtil.getGlowComposite());
g.setColor(UIManager.getColor("hoverHighlight"));
PaintUtil.fillRoundRect((Graphics2D) g, 0, 0, getWidth(), getHeight(), 10, false);
context.restore();
}
};
buttonPanel.setLayout(new LayoutManagerAdapter() {
private final int pad = 3;
@Override
public void layoutContainer(final Container parent) {
Dimension addPref = addButton.getPreferredSize();
Dimension delPref = deleteButton.getPreferredSize();
addButton.setBounds(pad, pad, addPref.width, addPref.height);
deleteButton.setBounds(2 * pad + addPref.width, pad, delPref.width, delPref.height);
}
@Override
public Dimension preferredLayoutSize(final Container parent) {
Dimension dim = addButton.getPreferredSize();
Dimension deleteSize = deleteButton.getPreferredSize();
dim.width += deleteSize.width + pad;
dim.height = Math.max(deleteSize.height, dim.height);
dim.width += 2 * pad;
dim.height += 2 * pad;
return dim;
}
@Override
public Dimension minimumLayoutSize(final Container parent) {
return preferredLayoutSize(parent);
}
});
buttonPanel.add(addButton);
buttonPanel.add(deleteButton);
buttonPanel.setOpaque(false);
return buttonPanel;
}
private static class MutableThemedLaf extends DarkLaf {
@Override

15
core/src/test/resources/icon/addEntry.svg

@ -0,0 +1,15 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 16 16" width="16" height="16">
<defs id="colors">
<linearGradient id="menuIconEnabled">
<stop offset="0" stop-color="#AFB1B3"/>
<stop offset="1" stop-color="#AFB1B3"/>
</linearGradient>
<linearGradient id="informationIconColor">
<stop offset="0" stop-color="#3592C4"/>
<stop offset="1" stop-color="#3592C4"/>
</linearGradient>
</defs>
<circle fill="url(#informationIconColor)" cx="11.5" cy="11.5" r="4.5"/>
<rect x="8" y="10.5" fill="url(#menuIconEnabled)" width="7" height="2"/>
<rect x="10.5" y="8" fill="url(#menuIconEnabled)" width="2" height="7"/>
</svg>

After

Width:  |  Height:  |  Size: 743 B

10
core/src/test/resources/icon/word.svg

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<defs id="colors">
<linearGradient id="menuIconEnabled">
<stop offset="0" stop-color="#AFB1B3"/>
<stop offset="1" stop-color="#AFB1B3"/>
</linearGradient>
</defs>
<path fill="url(#menuIconEnabled)" fill-rule="evenodd"
d="M8 6.4L6.246 13H4.4L2 3h2.031l1.384 7 1.754-7h1.662l1.754 7 1.384-7H14l-2.4 10H9.754z"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

Loading…
Cancel
Save