mirror of
https://github.com/hneemann/Digital.git
synced 2025-10-18 11:34:34 -04:00
250 lines
7.9 KiB
Java
250 lines
7.9 KiB
Java
package de.neemann.digital.gui.components;
|
|
|
|
import de.neemann.digital.core.ObservableValue;
|
|
import de.neemann.digital.gui.sync.Sync;
|
|
import de.neemann.digital.lang.Lang;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.event.DocumentEvent;
|
|
import javax.swing.event.DocumentListener;
|
|
import java.awt.*;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.KeyEvent;
|
|
import java.util.Arrays;
|
|
|
|
/**
|
|
* Dialog to edit a single value.
|
|
* Used to enter a multi bit input value.
|
|
*
|
|
* @author hneemann
|
|
* @author Rüdiger Heintz
|
|
*/
|
|
public final class SingleValueDialog extends JDialog {
|
|
|
|
private enum InMode {
|
|
HEX(Lang.get("attr_dialogHex")),
|
|
DECIMAL(Lang.get("attr_dialogDecimal")),
|
|
OCTAL(Lang.get("attr_dialogOctal")),
|
|
ASCII(Lang.get("attr_dialogAscii")),
|
|
// highZ needs to be the last entry!! See InMode#values(boolean)
|
|
HIGHZ(Lang.get("attr_dialogHighz"));
|
|
|
|
private String langText;
|
|
|
|
InMode(String langKey) {
|
|
this.langText = langKey;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return langText;
|
|
}
|
|
|
|
public static InMode[] values(boolean supportsHighZ) {
|
|
if (supportsHighZ) {
|
|
return values();
|
|
} else {
|
|
return Arrays.copyOf(values(), values().length - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private final JTextField textField;
|
|
private final boolean supportsHighZ;
|
|
private final JComboBox<InMode> formatComboBox;
|
|
private JCheckBox[] checkBoxes;
|
|
private boolean programmaticModifyingFormat = false;
|
|
private long editValue;
|
|
private boolean ok = false;
|
|
|
|
private SingleValueDialog(Point pos, ObservableValue value) {
|
|
super((Frame) null, Lang.get("attr_dialogTitle"), true);
|
|
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
|
|
|
editValue = value.getValue();
|
|
supportsHighZ = value.supportsHighZ();
|
|
|
|
textField = new JTextField(10);
|
|
textField.setHorizontalAlignment(JTextField.RIGHT);
|
|
formatComboBox = new JComboBox<>(InMode.values(supportsHighZ));
|
|
formatComboBox.addActionListener(actionEvent -> {
|
|
if (!programmaticModifyingFormat)
|
|
setLongToDialog(editValue);
|
|
});
|
|
|
|
JPanel panel = new JPanel(new DialogLayout());
|
|
panel.add(formatComboBox, DialogLayout.LABEL);
|
|
panel.add(textField, DialogLayout.INPUT);
|
|
panel.add(new JLabel(Lang.get("attr_dialogBinary")), DialogLayout.LABEL);
|
|
panel.add(createCheckBoxPanel(value.getBits(), editValue), DialogLayout.INPUT);
|
|
getContentPane().add(panel);
|
|
|
|
textField.getDocument().addDocumentListener(new MyDocumentListener(() -> setStringToDialog(textField.getText())));
|
|
|
|
if (value.isHighZ())
|
|
formatComboBox.setSelectedItem(InMode.HIGHZ);
|
|
else
|
|
setLongToDialog(editValue);
|
|
|
|
JButton okButton = new JButton(new AbstractAction(Lang.get("ok")) {
|
|
@Override
|
|
public void actionPerformed(ActionEvent actionEvent) {
|
|
ok = true;
|
|
dispose();
|
|
}
|
|
});
|
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
|
buttonPanel.add(okButton);
|
|
getContentPane().add(buttonPanel, BorderLayout.EAST);
|
|
|
|
getRootPane().setDefaultButton(okButton);
|
|
getRootPane().registerKeyboardAction(actionEvent -> dispose(),
|
|
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
|
|
pack();
|
|
setLocation(pos.x, pos.y);
|
|
textField.requestFocus();
|
|
textField.select(0, Integer.MAX_VALUE);
|
|
}
|
|
|
|
private JPanel createCheckBoxPanel(int bits, long value) {
|
|
JPanel p = new JPanel();
|
|
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
|
|
checkBoxes = new JCheckBox[bits];
|
|
for (int i = bits - 1; i >= 0; i--) {
|
|
final int bit = i;
|
|
checkBoxes[bit] = new JCheckBox("", (value & (1L << bit)) != 0);
|
|
checkBoxes[bit].setBorder(null);
|
|
checkBoxes[bit].addActionListener(actionEvent -> setBit(bit, checkBoxes[bit].isSelected()));
|
|
p.add(checkBoxes[bit]);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
private void setBit(int bitNum, boolean set) {
|
|
if (set)
|
|
editValue |= 1L << bitNum;
|
|
else
|
|
editValue &= ~(1L << bitNum);
|
|
|
|
if (getSelectedFormat().equals(InMode.HIGHZ))
|
|
setSelectedFormat(InMode.HEX);
|
|
|
|
setLongToDialog(editValue);
|
|
}
|
|
|
|
private void setLongToDialog(long editValue) {
|
|
switch (getSelectedFormat()) {
|
|
case ASCII:
|
|
char val = (char) (editValue);
|
|
textField.setText("\'" + val + "\'");
|
|
textField.setCaretPosition(1);
|
|
break;
|
|
case DECIMAL:
|
|
textField.setText(Long.toString(editValue));
|
|
break;
|
|
case HEX:
|
|
textField.setText("0x" + Long.toHexString(editValue));
|
|
break;
|
|
case OCTAL:
|
|
textField.setText("0" + Long.toOctalString(editValue));
|
|
break;
|
|
case HIGHZ:
|
|
textField.setText("?");
|
|
break;
|
|
default:
|
|
}
|
|
textField.requestFocus();
|
|
}
|
|
|
|
private InMode getSelectedFormat() {
|
|
return (InMode) formatComboBox.getSelectedItem();
|
|
}
|
|
|
|
private void setSelectedFormat(InMode format) {
|
|
if (!getSelectedFormat().equals(format)) {
|
|
programmaticModifyingFormat = true;
|
|
formatComboBox.setSelectedItem(format);
|
|
programmaticModifyingFormat = false;
|
|
}
|
|
}
|
|
|
|
private void setStringToDialog(String text) {
|
|
text = text.trim();
|
|
if (text.length() > 0) {
|
|
if (text.contains("?") && supportsHighZ) {
|
|
setSelectedFormat(InMode.HIGHZ);
|
|
editValue = 0;
|
|
} else if (text.charAt(0) == '\'') {
|
|
setSelectedFormat(InMode.ASCII);
|
|
if (text.length() > 1) {
|
|
editValue = text.charAt(1);
|
|
} else {
|
|
editValue = 0;
|
|
}
|
|
} else {
|
|
if (text.startsWith("0x"))
|
|
setSelectedFormat(InMode.HEX);
|
|
else if (text.startsWith("0"))
|
|
setSelectedFormat(InMode.OCTAL);
|
|
else
|
|
setSelectedFormat(InMode.DECIMAL);
|
|
try {
|
|
editValue = Long.decode(text);
|
|
} catch (NumberFormatException e) {
|
|
// do nothing on error
|
|
}
|
|
}
|
|
for (int i = 0; i < checkBoxes.length; i++)
|
|
checkBoxes[i].setSelected((editValue & (1L << i)) != 0);
|
|
}
|
|
}
|
|
|
|
private boolean showDialog() {
|
|
setVisible(true);
|
|
return ok;
|
|
}
|
|
|
|
/**
|
|
* Edits a single value
|
|
*
|
|
* @param pos the position to pop up the dialog
|
|
* @param value the value to edit
|
|
*/
|
|
public static void editValue(Point pos, ObservableValue value, Sync modelSync) {
|
|
SingleValueDialog svd = new SingleValueDialog(pos, value);
|
|
if (svd.showDialog()) {
|
|
if (svd.getSelectedFormat().equals(InMode.HIGHZ)) {
|
|
modelSync.access(() -> value.setHighZ(true));
|
|
} else {
|
|
modelSync.access(() -> value.set(svd.editValue, false));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private static final class MyDocumentListener implements DocumentListener {
|
|
private final Runnable runnable;
|
|
|
|
private MyDocumentListener(Runnable runnable) {
|
|
this.runnable = runnable;
|
|
}
|
|
|
|
@Override
|
|
public void insertUpdate(DocumentEvent documentEvent) {
|
|
runnable.run();
|
|
}
|
|
|
|
@Override
|
|
public void removeUpdate(DocumentEvent documentEvent) {
|
|
runnable.run();
|
|
}
|
|
|
|
@Override
|
|
public void changedUpdate(DocumentEvent documentEvent) {
|
|
runnable.run();
|
|
}
|
|
}
|
|
}
|