/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.ui.components.SplineEditor;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.Evaluator;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
import org.openide.util.NbBundle;
class SplineControlPanel extends JPanel {
private SplineDisplay display;
private int linesCount = 0;
private Animator controller;
private SplineEditor editor;
SplineControlPanel(SplineEditor editor) {
super(new BorderLayout());
this.editor = editor;
add(buildEquationDisplay(), BorderLayout.CENTER);
add(buildDebugControls(), BorderLayout.EAST);
}
private Component buildDebugControls() {
JPanel debugPanel = new JPanel(new GridBagLayout());
debugPanel.add(Box.createHorizontalStrut(150),
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 0.0,
GridBagConstraints.LINE_START,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 0),
0, 0));
// button = addButton(debugPanel, "Create");
// button.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// JFileChooser chooser = new JFileChooser(".");
// int choice = chooser.showSaveDialog(SplineControlPanel.this);
// if (choice == JFileChooser.CANCEL_OPTION) {
// return;
// }
// File file = chooser.getSelectedFile();
// try {
// OutputStream out = new FileOutputStream(file);
// display.saveAsTemplate(out);
// out.close();
// } catch (FileNotFoundException e1) {
// } catch (IOException e1) {
// }
// }
// });
addSeparator(debugPanel, NbBundle.getMessage(SplineEditor.class, "splineEditor_templates"));
debugPanel.add(createTemplates(),
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 0),
0, 0));
JButton saveTemplate = addButton(debugPanel, "Enregistrer");
JButton removeTemplate = addButton(debugPanel, "Supprimer");
saveTemplate.setEnabled(false);
removeTemplate.setEnabled(false);
addEmptySpace(debugPanel, 6);
addSeparator(debugPanel, NbBundle.getMessage(SplineEditor.class, "splineEditor_controls"));
JButton closeButton = addButton(debugPanel, NbBundle.getMessage(SplineEditor.class, "splineEditor_close"));
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
editor.dispose();
}
});
addEmptySpace(debugPanel, 6);
debugPanel.add(Box.createVerticalGlue(),
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 1.0,
GridBagConstraints.LINE_START,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 0),
0, 0));
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.add(new JSeparator(JSeparator.VERTICAL), BorderLayout.WEST);
wrapper.add(debugPanel);
wrapper.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 6));
return wrapper;
}
private Component createTemplates() {
DefaultListModel model = new DefaultListModel();
model.addElement(createTemplate(0.0, 0.0, 1.0, 1.0));
model.addElement(createTemplate(0.0, 1.0, 0.0, 1.0));
model.addElement(createTemplate(0.0, 1.0, 1.0, 1.0));
model.addElement(createTemplate(0.0, 1.0, 1.0, 0.0));
model.addElement(createTemplate(1.0, 0.0, 0.0, 1.0));
model.addElement(createTemplate(1.0, 0.0, 1.0, 1.0));
model.addElement(createTemplate(1.0, 0.0, 1.0, 0.0));
JList list = new JList(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new TemplateCellRenderer());
list.addListSelectionListener(new TemplateSelectionHandler());
JScrollPane pane = new JScrollPane(list);
pane.getViewport().setPreferredSize(new Dimension(98, 97 * 3));
return pane;
}
private JButton addButton(JPanel debugPanel, String label) {
JButton button;
debugPanel.add(button = new JButton(label),
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(3, 0, 0, 0),
0, 0));
return button;
}
private String formatPoint(Point2D p) {
NumberFormat formatter = getNumberFormatter();
return "" + formatter.format(p.getX()) + ", " + formatter.format(p.getY());
}
private Component buildEquationDisplay() {
JPanel panel = new JPanel(new BorderLayout());
display = new SplineDisplay();
/*display.addPropertyChangeListener("control1", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
labelControl1.setText(formatPoint(display.getControl1()));
}
});*/
panel.add(display, BorderLayout.NORTH);
return panel;
}
private JLabel addDebugLabel(JPanel panel, String label, String value) {
JLabel labelComponent = new JLabel(label);
panel.add(labelComponent,
new GridBagConstraints(0, linesCount,
1, 1,
0.5, 0.0,
GridBagConstraints.LINE_END,
GridBagConstraints.NONE,
new Insets(0, 6, 0, 0),
0, 0));
labelComponent = new JLabel(value);
panel.add(labelComponent,
new GridBagConstraints(1, linesCount++,
1, 1,
0.5, 0.0,
GridBagConstraints.LINE_START,
GridBagConstraints.NONE,
new Insets(0, 6, 0, 0),
0, 0));
return labelComponent;
}
private void addEmptySpace(JPanel panel, int size) {
panel.add(Box.createVerticalStrut(size),
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.VERTICAL,
new Insets(6, 0, 0, 0),
0, 0));
}
private void addSeparator(JPanel panel, String label) {
JPanel innerPanel = new JPanel(new GridBagLayout());
innerPanel.add(new JLabel(label),
new GridBagConstraints(0, 0,
1, 1,
0.0, 0.0,
GridBagConstraints.LINE_START,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 0),
0, 0));
innerPanel.add(new JSeparator(),
new GridBagConstraints(1, 0,
1, 1,
0.9, 0.0,
GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL,
new Insets(0, 6, 0, 6),
0, 0));
panel.add(innerPanel,
new GridBagConstraints(0, linesCount++,
2, 1,
1.0, 0.0,
GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL,
new Insets(6, 6, 6, 0),
0, 0));
}
private Evaluator point2dInterpolator = new Point2DNonLinearInterpolator();
private class Point2DNonLinearInterpolator extends Evaluator<Point2D> {
private Point2D value;
@Override
public Point2D evaluate(Point2D v0, Point2D v1,
float fraction) {
Point2D value = (Point2D) v0.clone();
if (v0 != v1) {
double x = value.getX();
x += (v1.getX() - v0.getX()) * fraction;
double y = value.getY();
y += (v1.getY() - v0.getY()) * fraction;
value.setLocation(x, y);
} else {
value.setLocation(v0.getX(), v0.getY());
}
return value;
}
}
private class TemplateSelectionHandler implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
JList list = (JList) e.getSource();
Template template = (Template) list.getSelectedValue();
if (template != null) {
if (controller != null && controller.isRunning()) {
controller.stop();
}
controller = new Animator(300,
new PropertySetter(display, "control1",
point2dInterpolator, display.getControl1(),
template.getControl1()));
controller.setResolution(10);
controller.addTarget(new PropertySetter(display, "control2",
point2dInterpolator, display.getControl2(),
template.getControl2()));
controller.start();
}
}
}
private static NumberFormat getNumberFormatter() {
NumberFormat formatter = NumberFormat.getInstance(Locale.ENGLISH);
formatter.setMinimumFractionDigits(2);
formatter.setMaximumFractionDigits(2);
return formatter;
}
private static Template createTemplate(double x1, double y1, double x2, double y2) {
return new Template(new Point2D.Double(x1, y1),
new Point2D.Double(x2, y2));
}
private static class TemplateCellRenderer extends DefaultListCellRenderer {
private boolean isSelected;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Template template = (Template) value;
this.setBackground(Color.WHITE);
this.setIcon(new ImageIcon(template.getImage()));
this.isSelected = isSelected;
return this;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (isSelected) {
g.setColor(new Color(0.0f, 0.0f, 0.7f, 0.1f));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
private static class Template {
private Point2D control1;
private Point2D control2;
private Image image;
public Template(Point2D control1, Point2D control2) {
this.control1 = control1;
this.control2 = control2;
}
public Point2D getControl1() {
return control1;
}
public Point2D getControl2() {
return control2;
}
public Image getImage() {
if (image == null) {
NumberFormat formatter = getNumberFormatter();
String name = "";
name += formatter.format(control1.getX()) + '-' + formatter.format(control1.getY());
name += '-';
name += formatter.format(control2.getX()) + '-' + formatter.format(control2.getY());
try {
image = ImageIO.read(getClass().getResourceAsStream("images/templates/" + name + ".png"));
} catch (IOException e) {
}
}
return image;
}
}
public SplineDisplay getDisplay() {
return display;
}
}