/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * logisim-evolution is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.data; import java.awt.Color; import java.awt.Component; import java.awt.Font; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.plaf.basic.BasicComboBoxRenderer; import com.bric.swing.ColorPicker; import com.cburch.logisim.util.FontUtil; import com.cburch.logisim.util.JInputComponent; import com.cburch.logisim.util.StringGetter; import com.connectina.swing.fontchooser.JFontChooser; public class Attributes { private static class BooleanAttribute extends OptionAttribute<Boolean> { private static Boolean[] vals = { Boolean.TRUE, Boolean.FALSE }; private BooleanAttribute(String name, StringGetter disp) { super(name, disp, vals); } @Override public Boolean parse(String value) { Boolean b = Boolean.valueOf(value); return vals[b.booleanValue() ? 0 : 1]; } @Override public String toDisplayString(Boolean value) { if (value.booleanValue()) return Strings.get("booleanTrueOption"); else return Strings.get("booleanFalseOption"); } } private static class ColorAttribute extends Attribute<Color> { public ColorAttribute(String name, StringGetter desc) { super(name, desc); } @Override public java.awt.Component getCellEditor(Color value) { Color init = value == null ? Color.WHITE : value; return new ColorChooser(init); } private String hex(int value) { if (value >= 16) return Integer.toHexString(value); else return "0" + Integer.toHexString(value); } @Override public Color parse(String value) { if (value.length() == 9) { int r = Integer.parseInt(value.substring(1, 3), 16); int g = Integer.parseInt(value.substring(3, 5), 16); int b = Integer.parseInt(value.substring(5, 7), 16); int a = Integer.parseInt(value.substring(7, 9), 16); return new Color(r, g, b, a); } else { return Color.decode(value); } } @Override public String toDisplayString(Color value) { return toStandardString(value); } @Override public String toStandardString(Color c) { String ret = "#" + hex(c.getRed()) + hex(c.getGreen()) + hex(c.getBlue()); return c.getAlpha() == 255 ? ret : ret + hex(c.getAlpha()); } } private static class ColorChooser extends ColorPicker implements JInputComponent { /** * */ private static final long serialVersionUID = 1L; ColorChooser(Color initial) { if (initial != null) setColor(initial); setOpacityVisible(true); } public Object getValue() { return getColor(); } public void setValue(Object value) { setColor((Color) value); } } private static class ConstantGetter implements StringGetter { private String str; public ConstantGetter(String str) { this.str = str; } /* * public String get() { return str; } * * @Override public String toString() { return get(); } */ public String toString() { return str; } } private static class DirectionAttribute extends OptionAttribute<Direction> { private static Direction[] vals = { Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST, }; public DirectionAttribute(String name, StringGetter disp) { super(name, disp, vals); } @Override public Direction parse(String value) { return Direction.parse(value); } @Override public String toDisplayString(Direction value) { return value == null ? "???" : value.toDisplayString(); } } private static class DoubleAttribute extends Attribute<Double> { private DoubleAttribute(String name, StringGetter disp) { super(name, disp); } @Override public Double parse(String value) { return Double.valueOf(value); } } private static class FontAttribute extends Attribute<Font> { private FontAttribute(String name, StringGetter disp) { super(name, disp); } @Override public java.awt.Component getCellEditor(Font value) { return new FontChooser(value); } @Override public Font parse(String value) { return Font.decode(value); } @Override public String toDisplayString(Font f) { if (f == null) return "???"; return f.getFamily() + " " + FontUtil.toStyleDisplayString(f.getStyle()) + " " + f.getSize(); } @Override public String toStandardString(Font f) { return f.getFamily() + " " + FontUtil.toStyleStandardString(f.getStyle()) + " " + f.getSize(); } } private static class FontChooser extends JFontChooser implements JInputComponent { /** * */ private static final long serialVersionUID = 1L; FontChooser(Font initial) { super(initial); } public Object getValue() { return getSelectedFont(); } public void setValue(Object value) { setSelectedFont((Font) value); } } private static class HexIntegerAttribute extends Attribute<Integer> { private HexIntegerAttribute(String name, StringGetter disp) { super(name, disp); } @Override public Integer parse(String value) { value = value.toLowerCase(); if (value.startsWith("0x")) { value = value.substring(2); return Integer.valueOf((int) Long.parseLong(value, 16)); } else if (value.startsWith("0b")) { value = value.substring(2); return Integer.valueOf((int) Long.parseLong(value, 2)); } else if (value.startsWith("0") && value.length() > 1) { value = value.substring(1); return Integer.valueOf((int) Long.parseLong(value, 8)); } else { return Integer.valueOf((int) Long.parseLong(value, 10)); } } @Override public String toDisplayString(Integer value) { int val = value.intValue(); return "0x" + Integer.toHexString(val); } @Override public String toStandardString(Integer value) { return toDisplayString(value); } } private static class IntegerAttribute extends Attribute<Integer> { private IntegerAttribute(String name, StringGetter disp) { super(name, disp); } @Override public Integer parse(String value) { return Integer.valueOf(value); } } private static class IntegerRangeAttribute extends Attribute<Integer> { Integer[] options = null; int start; int end; private IntegerRangeAttribute(String name, StringGetter disp, int start, int end) { super(name, disp); this.start = start; this.end = end; } @SuppressWarnings("rawtypes") @Override public java.awt.Component getCellEditor(Integer value) { if (end - start + 1 > 32) { return super.getCellEditor(value); } else { if (options == null) { options = new Integer[end - start + 1]; for (int i = start; i <= end; i++) { options[i - start] = Integer.valueOf(i); } } JComboBox combo = new JComboBox<>(options); if (value == null) combo.setSelectedIndex(-1); else combo.setSelectedItem(value); return combo; } } @Override public Integer parse(String value) { int v = (int) Long.parseLong(value); if (v < start) throw new NumberFormatException("integer too small"); if (v > end) throw new NumberFormatException("integer too large"); return Integer.valueOf(v); } } private static class LocationAttribute extends Attribute<Location> { public LocationAttribute(String name, StringGetter desc) { super(name, desc); } @Override public Location parse(String value) { return Location.parse(value); } } private static class OptionAttribute<V> extends Attribute<V> { private V[] vals; private OptionAttribute(String name, StringGetter disp, V[] vals) { super(name, disp); this.vals = vals; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public java.awt.Component getCellEditor(Object value) { JComboBox combo = new JComboBox<>(vals); combo.setRenderer(new OptionComboRenderer<V>(this)); if (value == null) combo.setSelectedIndex(-1); else combo.setSelectedItem(value); return combo; } @Override public V parse(String value) { for (int i = 0; i < vals.length; i++) { if (value.equals(vals[i].toString())) { return vals[i]; } } throw new NumberFormatException("value not among choices"); } @Override public String toDisplayString(V value) { if (value instanceof AttributeOptionInterface) { return ((AttributeOptionInterface) value).toDisplayString(); } else { return value.toString(); } } } private static class OptionComboRenderer<V> extends BasicComboBoxRenderer { private static final long serialVersionUID = 1L; Attribute<V> attr; OptionComboRenderer(Attribute<V> attr) { this.attr = attr; } @SuppressWarnings("rawtypes") @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component ret = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (ret instanceof JLabel) { @SuppressWarnings("unchecked") V val = (V) value; ((JLabel) ret).setText(value == null ? "" : attr .toDisplayString(val)); } return ret; } } private static class StringAttribute extends Attribute<String> { private StringAttribute(String name, StringGetter disp) { super(name, disp); } @Override public String parse(String value) { return value; } } private static class HiddenAttribute extends Attribute<String> { private HiddenAttribute() { super(); } @Override public String parse(String value) { return value; } } public static Attribute<String> forHidden() { return new HiddenAttribute(); } public static Attribute<BitWidth> forBitWidth(String name) { return forBitWidth(name, getter(name)); } public static Attribute<BitWidth> forBitWidth(String name, int min, int max) { return forBitWidth(name, getter(name), min, max); } public static Attribute<BitWidth> forBitWidth(String name, StringGetter disp) { return new BitWidth.Attribute(name, disp); } public static Attribute<BitWidth> forBitWidth(String name, StringGetter disp, int min, int max) { return new BitWidth.Attribute(name, disp, min, max); } public static Attribute<Boolean> forBoolean(String name) { return forBoolean(name, getter(name)); } public static Attribute<Boolean> forBoolean(String name, StringGetter disp) { return new BooleanAttribute(name, disp); } public static Attribute<Color> forColor(String name) { return forColor(name, getter(name)); } public static Attribute<Color> forColor(String name, StringGetter disp) { return new ColorAttribute(name, disp); } public static Attribute<Direction> forDirection(String name) { return forDirection(name, getter(name)); } public static Attribute<Direction> forDirection(String name, StringGetter disp) { return new DirectionAttribute(name, disp); } public static Attribute<Double> forDouble(String name) { return forDouble(name, getter(name)); } public static Attribute<Double> forDouble(String name, StringGetter disp) { return new DoubleAttribute(name, disp); } public static Attribute<Font> forFont(String name) { return forFont(name, getter(name)); } public static Attribute<Font> forFont(String name, StringGetter disp) { return new FontAttribute(name, disp); } public static Attribute<Integer> forHexInteger(String name) { return forHexInteger(name, getter(name)); } public static Attribute<Integer> forHexInteger(String name, StringGetter disp) { return new HexIntegerAttribute(name, disp); } public static Attribute<Integer> forInteger(String name) { return forInteger(name, getter(name)); } public static Attribute<Integer> forInteger(String name, StringGetter disp) { return new IntegerAttribute(name, disp); } public static Attribute<Integer> forIntegerRange(String name, int start, int end) { return forIntegerRange(name, getter(name), start, end); } public static Attribute<Integer> forIntegerRange(String name, StringGetter disp, int start, int end) { return new IntegerRangeAttribute(name, disp, start, end); } public static Attribute<Location> forLocation(String name) { return forLocation(name, getter(name)); } public static Attribute<Location> forLocation(String name, StringGetter disp) { return new LocationAttribute(name, disp); } public static Attribute<?> forOption(String name, Object[] vals) { return forOption(name, getter(name), vals); } public static <V> Attribute<V> forOption(String name, StringGetter disp, V[] vals) { return new OptionAttribute<V>(name, disp, vals); } // // methods with display name == standard name // public static Attribute<String> forString(String name) { return forString(name, getter(name)); } // // methods with internationalization support // public static Attribute<String> forString(String name, StringGetter disp) { return new StringAttribute(name, disp); } private static StringGetter getter(String s) { return new ConstantGetter(s); } private Attributes() { } }