package nodebox.client;
import nodebox.Icons;
import nodebox.node.*;
import nodebox.ui.SingleLineSplitPane;
import nodebox.ui.SwingUtils;
import nodebox.ui.Theme;
import javax.swing.*;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class NodeAttributesEditor extends JPanel implements ListSelectionListener {
private static final String NODE_SETTINGS = "Settings";
private NodeAttributesDialog dialog;
private Port selectedPort = null;
private PortList portList;
private JPanel editorPanel;
private JButton removeButton;
private JButton addButton;
private JPanel leftPanel;
public NodeAttributesEditor(NodeAttributesDialog dialog) {
setLayout(new BorderLayout(0, 0));
this.dialog = dialog;
leftPanel = new JPanel(new BorderLayout(5, 0));
portList = new PortList();
reloadPortList();
//portList.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
addButton = new JButton(new Icons.PlusIcon());
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addPort();
}
});
removeButton = new JButton(new Icons.MinusIcon());
removeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeSelectedPort();
}
});
JButton upButton = new JButton(new Icons.ArrowIcon(Icons.ArrowIcon.NORTH));
upButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
moveUp();
}
});
JButton downButton = new JButton(new Icons.ArrowIcon(Icons.ArrowIcon.SOUTH));
downButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
moveDown();
}
});
buttonPanel.add(addButton);
buttonPanel.add(removeButton);
//buttonPanel.add(upButton);
//buttonPanel.add(downButton);
//portList.getSelectionModel().addListSelectionListener(this);
//portList.setCellRenderer(parameterCellRenderer);
//portList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
leftPanel.add(portList, BorderLayout.CENTER);
leftPanel.add(buttonPanel, BorderLayout.SOUTH);
editorPanel = new JPanel(new BorderLayout());
editorPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
JSplitPane split = new SingleLineSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, editorPanel);
split.setDividerLocation(150);
split.setResizeWeight(0.25);
add(split, BorderLayout.CENTER);
if (getNode().getInputs().size() > 0)
portList.setSelectedIndex(0);
}
private void reloadPortList() {
portList.removeAll();
// Add the Node metadata.
portList.addHeader("NODE");
portList.addNodeSettings();
portList.addHeader("PORTS");
for (Port p : getNode().getInputs()) {
portList.addPort(p);
}
revalidate();
leftPanel.repaint();
}
private void settingsSelected() {
editorPanel.removeAll();
NodeSettingsEditor editor = new NodeSettingsEditor(dialog);
editorPanel.add(editor, BorderLayout.CENTER);
editorPanel.revalidate();
selectedPort = null;
}
private void portSelected(Port port) {
editorPanel.removeAll();
PortAttributesEditor editor = new PortAttributesEditor(dialog, port.getName());
editorPanel.add(editor, BorderLayout.CENTER);
editorPanel.revalidate();
selectedPort = port;
}
private void addPort() {
NewPortDialog d = new NewPortDialog();
d.setVisible(true);
String portName = d.portName;
if (portName != null) {
dialog.addPort(getNode(), portName, d.portType);
reloadPortList();
portList.setSelectedValue(getNode().getInput(portName), true);
}
}
private void removeSelectedPort() {
if (selectedPort == null) return;
dialog.removePort(getNode(), selectedPort.getName());
reloadPortList();
editorPanel.removeAll();
editorPanel.revalidate();
editorPanel.repaint();
selectedPort = null;
}
private void moveDown() {
}
private void moveUp() {
}
public Node getNode() {
return dialog.getNode();
}
public void valueChanged(ListSelectionEvent e) {
if (selectedPort == portList.getSelectedValue()) return;
selectedPort = (Port) portList.getSelectedValue();
if (selectedPort == null) {
removeButton.setEnabled(false);
} else {
removeButton.setEnabled(true);
}
//parameterPanel.revalidate();
}
private class PortListModel implements ListModel {
public PortListModel() {
}
public int getSize() {
return getNode().getInputs().size();
}
public Object getElementAt(int index) {
return getNode().getInputs().get(index);
}
public void addListDataListener(ListDataListener l) {
// Not implemented
}
public void removeListDataListener(ListDataListener l) {
// Not implemented
}
}
private class PortCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Port port = (Port) value;
String displayValue = port.getDisplayLabel() + " (" + port.getName() + ")";
return super.getListCellRendererComponent(list, displayValue, index, isSelected, cellHasFocus);
}
}
private class SourceLabel extends JComponent {
private String text;
private Object source;
private boolean selected;
private SourceLabel(String text, Object source) {
this.text = text;
this.source = source;
setMinimumSize(new Dimension(100, 25));
setMaximumSize(new Dimension(500, 25));
setPreferredSize(new Dimension(140, 25));
setAlignmentX(JComponent.LEFT_ALIGNMENT);
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
repaint();
}
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if (selected) {
Rectangle clip = g2.getClipBounds();
g2.setColor(Theme.NODE_ATTRIBUTES_PARAMETER_COLOR);
g2.fillRect(clip.x, clip.y, clip.width, clip.height);
}
g2.setFont(Theme.SMALL_FONT);
if (selected) {
g2.setColor(Color.WHITE);
} else {
g2.setColor(Color.BLACK);
}
g2.drawString(text, 15, 18);
}
}
private class PortList extends JPanel {
private SourceLabel selectedLabel;
private Map<Object, SourceLabel> labelMap = new HashMap<Object, SourceLabel>();
private PortList() {
super(null);
Dimension d = new Dimension(140, 500);
setBackground(Theme.NODE_ATTRIBUTES_PARAMETER_LIST_BACKGROUND_COLOR);
setBorder(null);
setOpaque(true);
setPreferredSize(d);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}
public void addNodeSettings() {
final SourceLabel label = new SourceLabel(NODE_SETTINGS, NODE_SETTINGS);
label.addMouseListener(new MouseInputAdapter() {
public void mouseClicked(MouseEvent e) {
setSelectedLabel(label);
}
});
labelMap.put(NODE_SETTINGS, label);
add(label);
}
public void addPort(final Port p) {
final SourceLabel label = new SourceLabel(p.getName(), p);
label.addMouseListener(new MouseInputAdapter() {
public void mouseClicked(MouseEvent e) {
setSelectedLabel(label);
}
});
labelMap.put(p, label);
add(label);
}
/**
* Add a header label that cannot be selected.
*
* @param s the name of the header.
*/
public void addHeader(String s) {
JLabel header = new JLabel(s);
header.setForeground(Theme.TEXT_HEADER_COLOR);
header.setFont(Theme.SMALL_BOLD_FONT);
header.setMinimumSize(new Dimension(100, 25));
header.setMaximumSize(new Dimension(500, 25));
header.setPreferredSize(new Dimension(140, 25));
header.setAlignmentX(JComponent.LEFT_ALIGNMENT);
header.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
add(header);
}
public void setSelectedLabel(SourceLabel label) {
if (selectedLabel != null)
selectedLabel.setSelected(false);
selectedLabel = label;
if (selectedLabel != null) {
selectedLabel.setSelected(true);
if (label.source.equals(NODE_SETTINGS)) {
settingsSelected();
} else if (label.source instanceof Port)
portSelected((Port) label.source);
else
throw new AssertionError("Unknown label source " + label.source);
}
}
public void setSelectedIndex(int i) {
// TODO: Implement
}
public void setSelectedValue(Object value, boolean shouldScroll) {
SourceLabel label = labelMap.get(value);
assert label != null;
setSelectedLabel(label);
}
public Object getSelectedValue() {
return null;
}
}
private class NewPortDialog extends JDialog {
private String portName = null;
private String portType = null;
public NewPortDialog() {
setTitle("Add new port");
setModal(true);
setResizable(false);
// Main
setLayout(new BorderLayout(5, 5));
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(mainPanel, BorderLayout.CENTER);
// name
JPanel namePanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
namePanel.add(new JLabel("Port name: "));
final JTextField nameField = new JTextField("", 20);
namePanel.add(nameField);
// type
JPanel typePanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
typePanel.add(new JLabel("Type: "));
String[] types = new String[Port.STANDARD_TYPES.size() + 1];
Port.STANDARD_TYPES.toArray(types);
types[types.length - 1] = "custom";
final JComboBox box = new JComboBox(types);
typePanel.add(box);
// custom type
JPanel customTypePanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
customTypePanel.add(new JLabel("Custom Type: "));
final JTextField customTypeField = new JTextField("", 20);
customTypeField.setEnabled(false);
customTypePanel.add(customTypeField);
box.addActionListener (new ActionListener () {
public void actionPerformed(ActionEvent e) {
customTypeField.setEnabled(box.getSelectedItem().equals("custom"));
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
buttonPanel.add(Box.createHorizontalGlue());
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
dispose();
}
});
buttonPanel.add(cancelButton);
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
portName = nameField.getText();
String selectedType = (String) box.getSelectedItem();
portType = selectedType.equals("custom") ? customTypeField.getText().toLowerCase(Locale.US) : selectedType;
dispose();
}
});
buttonPanel.add(okButton);
mainPanel.add(namePanel);
mainPanel.add(Box.createVerticalStrut(10));
mainPanel.add(typePanel);
mainPanel.add(Box.createVerticalStrut(10));
mainPanel.add(customTypePanel);
mainPanel.add(Box.createVerticalStrut(10));
mainPanel.add(buttonPanel);
pack();
getRootPane().setDefaultButton(okButton);
KeyStroke escapeStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
getRootPane().registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}, escapeStroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
SwingUtils.centerOnScreen(this);
}
}
/*private static class AllControlsType extends Builtin {
protected Node createInstance() {
NodeLibrary library = new NodeLibrary("allcontrols");
Node n = Node.ROOT_NODE.newInstance(library, "allcontrols", Canvas.class);
n.addParameter("angle", Parameter.Type.FLOAT).setWidget(Parameter.Widget.ANGLE);
n.addParameter("color", Parameter.Type.COLOR).setWidget(Parameter.Widget.COLOR);
n.addParameter("file", Parameter.Type.STRING).setWidget(Parameter.Widget.FILE);
n.addParameter("float", Parameter.Type.FLOAT).setWidget(Parameter.Widget.FLOAT);
n.addParameter("font", Parameter.Type.STRING).setWidget(Parameter.Widget.FONT);
n.addParameter("gradient", Parameter.Type.COLOR).setWidget(Parameter.Widget.GRADIENT);
n.addParameter("image", Parameter.Type.STRING).setWidget(Parameter.Widget.IMAGE);
n.addParameter("int", Parameter.Type.INT).setWidget(Parameter.Widget.INT);
n.addParameter("menu", Parameter.Type.STRING).setWidget(Parameter.Widget.MENU);
n.addParameter("seed", Parameter.Type.INT).setWidget(Parameter.Widget.SEED);
n.addParameter("string", Parameter.Type.STRING).setWidget(Parameter.Widget.STRING);
n.addParameter("text", Parameter.Type.STRING).setWidget(Parameter.Widget.TEXT);
n.addParameter("toggle", Parameter.Type.INT).setWidget(Parameter.Widget.TOGGLE);
n.addParameter("noderef", Parameter.Type.STRING).setWidget(Parameter.Widget.NODEREF);
Parameter pMenu = n.getParameter("menu");
pMenu.addMenuItem("red", "Red");
pMenu.addMenuItem("green", "Green");
pMenu.addMenuItem("blue", "Blue");
pMenu.setValue("blue");
return n;
}
@Override
public Object cook(Node node, ProcessingContext context) {
return null;
}
} */
/* public static void main(String[] args) {
JFrame editorFrame = new JFrame();
Node node = new AllControlsType().createInstance();
node.addPort("shape");
editorFrame.getContentPane().add(new NodeAttributesEditor(node));
editorFrame.setSize(580, 710);
editorFrame.setResizable(false);
editorFrame.setLocationByPlatform(true);
editorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
editorFrame.setVisible(true);
} */
}