Package org.newdawn.slick.tools.peditor

Source Code of org.newdawn.slick.tools.peditor.GraphEditorWindow$GraphPanel

package org.newdawn.slick.tools.peditor;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;

import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.particles.ConfigurableEmitter;
import org.newdawn.slick.particles.ConfigurableEmitter.LinearInterpolator;

/**
* A visual control to allow the editing of linear interpolated values effecting
* the generated particles.
*
* @author void
*/
public class GraphEditorWindow extends JPanel {
  /** The list of values placed in the graph */
  private Hashtable values;
  /** The properties listed in the top left */
  private JComboBox properties;
  /** The panel with the main controls on */
  private DefaultPanel top;
  /** The panel displaying the current graph */
  private GraphPanel panel;

  /** The x axis label */
  private JLabel valueXLabel;
  /** The y axis label */
  private JLabel valueYLabel;

  /** The minimum value for the graph control */
  private JSpinner minSpinner;
  /** The maxium value for the graph control */
  private JSpinner maxSpinner;

  /** The color for lines on the graph */
  private static Color COLOR_LINE = new Color(0xEEEEEE);
  /** The color for points on the graph */
  private static Color COLOR_POINT = new Color(0xFFCC66);
  /** The color for point outlines on the graph */
  private static Color COLOR_POINT_OUTLINE = new Color(0x444444);
  /** The color for selectd points on the graph */
  private static Color COLOR_SELECTED_POINT = new Color(0xFFFFFF);
  /** The color for selectd point outlines on the graph */
  private static Color COLOR_SELECTED_POINT_OUTLINE = new Color(0x000000);
  /** The color for the legend text on the graph */
  private static Color COLOR_LEGEND = new Color(0x000000);
  /** The color for the legend background on the graph */
  private static Color COLOR_LEGEND_BACKGROUND = new Color(0x555566);
  /** The color for the legend grid on the graph */
  private static Color COLOR_LEGEND_GRID = new Color(0x333344);
  /** The color for the legend grid crosses on the graph */
  private static Color COLOR_LEGEND_GRID_CROSS = new Color(0x222233);
  /** The color for the background on the graph */
  private static Color COLOR_BACKGROUND = new Color(0x444455);
  /** The color for the labels on the graph */
  private static Color COLOR_LABEL = new Color(0x000000);

  /** The x axis label */
  private static final String TEXT_CURRENT_X = "Time: ";
  /** The y axis label */
  private static final String TEXT_CURRENT_Y = "Value: ";

  /**
   * Create a new graph editor window
   */
  public GraphEditorWindow() {
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    setBackground(COLOR_BACKGROUND);

    // window is divided into the top panel and the graph panel (see below)
    panel = new GraphPanel();
    top = createTopPanel();
    top.setEnabled(false);

    add(top);
    add(panel);

    // init the values
    values = new Hashtable();
  }

  /**
   * Set the emitter that is being controlled
   * 
   * @param emitter The emitter that is configured by this panel
   */
  public void setLinkedEmitter(ConfigurableEmitter emitter) {
    // set the title
    Window w = SwingUtilities.windowForComponent(this);
    if (w instanceof Frame)
      ((Frame) w).setTitle("Whiskas Gradient Editor (" + emitter.name
          + ")");

    // clear all values
    properties.removeAllItems();
    values.clear();
    panel.setInterpolator(null);
    enableControls();
  }

  /**
   * Create the top panel
   *
   * @return A fully configured component
   */
  private DefaultPanel createTopPanel() {
    DefaultPanel top = new DefaultPanel();
    top.setLayout(new BoxLayout(top, BoxLayout.X_AXIS));
    top.setAlignmentX(Component.LEFT_ALIGNMENT);
    top.setPreferredSize(new Dimension(Short.MAX_VALUE, 40));

    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // property label
    JLabel propLabel = new JLabel("Property");
    propLabel.setBounds(10, 20, 40, 20);
    propLabel.setForeground(COLOR_LABEL);
    top.add(propLabel);
    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // add properties combobox
    properties = new JComboBox();
    properties.setMaximumSize(new Dimension(100, 20));
    properties.setMinimumSize(new Dimension(100, 20));
    properties.setPreferredSize(new Dimension(100, 20));
    properties.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent event) {
        String item = (String) event.getItem();
        LinearInterpolator currentValue = (LinearInterpolator) values
            .get(item);
        panel.setInterpolator(currentValue);
      }
    });
    top.add(properties);
    top.add(Box.createRigidArea(new Dimension(10, 0)));

    // min label
    JLabel minLabel = new JLabel("Min");
    minLabel.setMaximumSize(new Dimension(100, 20));
    minLabel.setForeground(COLOR_LABEL);
    top.add(minLabel);
    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // min spinner
    minSpinner = new JSpinner(new SpinnerNumberModel(0, -1000, 1000, 1));
    minSpinner.setMaximumSize(new Dimension(100, 20));
    minSpinner.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        fireUpdated(e.getSource());
      }
    });
    top.add(minSpinner);
    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // max label
    JLabel maxLabel = new JLabel("Max");
    maxLabel.setMaximumSize(new Dimension(100, 20));
    maxLabel.setForeground(COLOR_LABEL);
    top.add(maxLabel);
    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // max spinner
    maxSpinner = new JSpinner(new SpinnerNumberModel(255, -1000, 1000, 1));
    maxSpinner.setMaximumSize(new Dimension(100, 20));
    maxSpinner.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        fireUpdated(e.getSource());
      }
    });
    top.add(maxSpinner);
    top.add(Box.createRigidArea(new Dimension(5, 0)));

    // spacer
    top.add(Box.createHorizontalGlue());

    // value x label
    valueXLabel = new JLabel(TEXT_CURRENT_X);
    valueXLabel.setMaximumSize(new Dimension(100, 20));
    valueXLabel.setForeground(COLOR_LABEL);
    top.add(valueXLabel);
    top.add(Box.createRigidArea(new Dimension(10, 0)));

    // value y label
    valueYLabel = new JLabel(TEXT_CURRENT_Y);
    valueYLabel.setMaximumSize(new Dimension(100, 20));
    valueYLabel.setForeground(COLOR_LABEL);
    top.add(valueYLabel);
    top.add(Box.createRigidArea(new Dimension(10, 0)));

    return top;
  }

  /**
   * Fire a notification that the panel has been changed
   *
   * @param control The source of the update
   */
  private void fireUpdated(Object control) {
    if (control.equals(minSpinner)) {
      int minY = ((Integer) minSpinner.getValue()).intValue();
      if (minY < panel.getWorldMaxY()) {
        panel.setWorldMinY(minY);
        panel.makeSureCurveFits();
        panel.repaint();
      } else {
        minSpinner.setValue(new Integer((int) panel.getWorldMinY()));
      }
    } else if (control.equals(maxSpinner)) {
      int maxY = ((Integer) maxSpinner.getValue()).intValue();
      if (maxY > panel.getWorldMinY()) {
        panel.setWorldMaxY(maxY);
        panel.makeSureCurveFits();
        panel.repaint();
      } else {
        maxSpinner.setValue(new Integer((int) panel.getWorldMaxY()));
      }
    }
  }

  /**
   * Register a configurable value with the graph panel
   *
   * @param value The value to be registered
    * @param name The name to display for this value
   */
  public void registerValue(LinearInterpolator value, String name) {
    // add to properties combobox
    properties.addItem(name);

    // add to value map
    values.put(name, value);

    // set as current interpolator
    panel.setInterpolator(value);

    // enable all input fields
    enableControls();
  }

  /**
   * Enable the controls for the graph
   */
  private void enableControls() {
    if (properties.getItemCount() > 0)
      top.setEnabled(true);
    else
      top.setEnabled(false);
  }

  /**
   * Remove a configurable value from the graph
   *
   * @param name The name of the value to be removed
   */
  public void removeValue(String name) {
    properties.removeItem(name);
    values.remove(name);

    if (properties.getItemCount() >= 1) {
      properties.setSelectedIndex(0);
    } else {
      panel.setInterpolator(null);
    }

    enableControls();
  }

  /**
   * Indicate that the first property should be displayed
   */
  public void setFirstProperty() {
    if (properties.getItemCount() > 0) {
      properties.setSelectedIndex(0);

      LinearInterpolator currentValue = (LinearInterpolator) values
          .get(properties.getSelectedItem());
      panel.setInterpolator(currentValue);
    }
  }

  /**
   * The actual panel the graph is drawn on
   *
   * @author void
   */
  public class GraphPanel extends JPanel {
    /** The list of points */
    private ArrayList curve;
    /** The value being configured */
    private LinearInterpolator value;

    /** The graph viewport minimum x value */
    private float viewportMinX;
    /** The graph viewport maximum x value */
    private float viewportMaxX;
    /** The graph viewport minimum y value */
    private float viewportMinY;
    /** The graph viewport maximum y value */
    private float viewportMaxY;
    /** The graph world minimum x value */
    private float worldMinX = 0.0f;
    /** The graph world maximum x value */
    private float worldMaxX = 1.0f;
    /** The graph world minimum y value */
    private float worldMinY = 0.0f;
    /** The graph world maximum y value */
    private float worldMaxY = 255.0f;

    /** The border size on the x axis */
    private float viewBorderX = 50;
    /** The border size of the y axis */
    private float viewBorderY = 25;

    /** The selected point for colour */
    private int colorSelectedPoint;
    /** The current point for colour */
    private int colorPoint;

    /** The mouse X position */
    private float mouseX;
    /** The mouse Y position */
    private float mouseY;

    /** The image displayed int he background of the panel */
    private BufferedImage backgroundImage;

    /**
     * Create a new graph panel
     */
    public GraphPanel() {
      setLayout(null);

      // load image
      backgroundImage = loadBackgroundImage();

      // mouse motion listener to forward events to the gradient
      this.addMouseMotionListener(new MouseMotionListener() {
        public void mouseDragged(MouseEvent e) {
          mouseDraggedEvent(e.getX(), e.getY(), e.isShiftDown());
        }

        public void mouseMoved(MouseEvent e) {
          mouseMovedEvent(e.getX(), e.getY());
        }
      });

      // mouse
      this.addMouseListener(new MouseListener() {
        public void mouseEntered(MouseEvent arg0) {
        }

        public void mouseExited(MouseEvent arg0) {
        }

        public void mousePressed(MouseEvent arg0) {
        }

        public void mouseReleased(MouseEvent arg0) {
        }

        public void mouseClicked(MouseEvent e) {
          mousePressedEvent(e.getX(), e.getY(),
              e.getButton() == MouseEvent.BUTTON1,
              e.getButton() == MouseEvent.BUTTON3,
              e.getButton() == MouseEvent.BUTTON2);
        }
      });
    }

    /**
     * Load a background image and apply it (add some style to whiskas =))
     *
     * @return The image to display in the background
     */
    private BufferedImage loadBackgroundImage() {
      InputStream in = ParticleEditor.class.getClassLoader()
          .getResourceAsStream(
              "org/newdawn/slick/tools/peditor/data/charlie.png");
      BufferedImage backgroundImage = null;
      try {
        backgroundImage = ImageIO.read(in);
      } catch (IOException e) {
        e.printStackTrace();
      }

      return backgroundImage;
    }

    /**
     * Set the interpolator being configured
     *
     * @param value The value to be configured
     */
    public void setInterpolator(LinearInterpolator value) {
      if (value == null) {
        this.value = null;
        this.curve = null;
      } else {
        this.value = value;
        curve = convertToCurvePointCurve(value.getCurve());

        minSpinner.setValue(new Integer(value.getMin()));
        maxSpinner.setValue(new Integer(value.getMax()));

        worldMinY = value.getMin();
        worldMaxY = value.getMax();

        repaint();
      }
    }

    /**
     * Change the current curve and make sure that the whole curve is in the
     * worldMinY and worldMaxY interval
     */
    private void makeSureCurveFits() {
      for (int i = 0; i < curve.size(); i++) {
        CurvePoint point = ((CurvePoint) curve.get(i));

        if (point.y > worldMaxY)
          point.y = worldMaxY;

        if (point.y < worldMinY)
          point.y = worldMinY;
      }
    }

    /**
     * Find the first selected point in the given curve
     *
     * @param curve The list of points to search
     * @return The index of the selected point
     */
    private int findSelectedPoint(ArrayList curve) {
      for (int i = 0; i < curve.size(); i++) {
        if (((CurvePoint) curve.get(i)).isSelected()) {
          return i;
        }
      }

      return -1;
    }

    /**
     * Return the index of the previous point in the given curve
     *
     * @param curve The list of points to search
     * @param idx The index of the current point
     * @return The index of the point that is previous to the point with the
     *         given index
     */
    private int getPrev(ArrayList curve, int idx) {
      if (idx == -1)
        return -1;

      if (idx <= 0 || idx >= curve.size() - 1)
        return -1;

      return idx - 1;
    }

    /**
     * Return the index of the next point in the given curve
     *
     * @param curve The list of points to search
     * @param idx The index of the current point
     * @return The index of the point that follows the point with the given
     *         index
     */
    private int getNext(ArrayList curve, int idx) {
      if (idx == -1)
        return -1;

      if (idx >= curve.size() - 1)
        return -1;

      return idx + 1;
    }

    /**
     * Drag a curve point based on the reception of an event
     *
     * @param x The new x position
     * @param y The new y position
     * @param shiftDown True if shift is pressed
     */
    public void mouseDraggedEvent(int x, int y, boolean shiftDown) {
      if (!isActive())
        return;

      int idx = findSelectedPoint(curve);
      if (idx != -1) {
        CurvePoint selected = (CurvePoint) curve.get(idx);
        CurvePoint world = viewToWorld(new CurvePoint(x, y));

        // let the first and last points only change in y
        if (selected == curve.get(0)
            || selected == curve.get(curve.size() - 1)) {
          selected.y = world.y;
        } else {
          selected.x = world.x;
          selected.y = world.y;
        }

        if (selected.x < worldMinX)
          selected.x = worldMinX;

        if (selected.x > worldMaxX)
          selected.x = worldMaxX;

        if (selected.y < worldMinY)
          selected.y = worldMinY;

        if (selected.y > worldMaxY)
          selected.y = worldMaxY;

        if (!shiftDown) {
          int prev = getPrev(curve, idx);
          int next = getNext(curve, idx);

          if (prev != -1) {
            if (selected.x < ((CurvePoint) curve.get(prev)).x)
              selected.x = ((CurvePoint) curve.get(prev)).x;
          }

          if (next != -1) {
            if (selected.x > ((CurvePoint) curve.get(next)).x)
              selected.x = ((CurvePoint) curve.get(next)).x;
          }
        }

        mouseX = x;
        mouseY = y;

        sortPoints();
        repaint();
      }
    }

    /**
     * Notified that the mouse pointer has moved
     *
     * @param x The x position of the new mouse position
     * @param y The y position of the new mouse position
     */
    public void mouseMovedEvent(int x, int y) {
      if (!isActive())
        return;

      CurvePoint posView = new CurvePoint(x, y);

      for (int i = 0; i < curve.size(); i++) {
        CurvePoint pWorld = (CurvePoint) curve.get(i);
        CurvePoint pView = worldToView((CurvePoint) curve.get(i));

        if ((posView.x > (pView.x - 12 / 2))
            && (posView.x < (pView.x + 12 / 2))
            && (posView.y > (pView.y - 12 / 2))
            && (posView.y < (pView.y + 12 / 2))) {
          ((CurvePoint) curve.get(i)).selected = true;
        } else {
          ((CurvePoint) curve.get(i)).selected = false;
        }
      }

      mouseX = x;
      mouseY = y;

      repaint();
    }

    /**
     * Notification that the mouse was pressed on the panel
     *
     * @param leftButton True if the left button was pressed
     * @param rightButton True if the right button was pressed
     * @param middleButton True if the middle button was pressed
     * @param x The x position of the mouse press
     * @param y The y position of the mouse press
     */
    public void mousePressedEvent(int x, int y, boolean leftButton,
        boolean rightButton, boolean middleButton) {
      if (!isActive())
        return;

      // right button -> remove selected point
      if (rightButton) {
        int idx = findSelectedPoint(curve);
        if (idx != -1) {
          // can't remove first and last points
          if (idx != 0 && idx != curve.size() - 1) {
            curve.remove(idx);
            repaint();
          }
        }
      } else if (leftButton) {
        int idx = findSelectedPoint(curve);
        if (idx == -1) {
          // only add points when nothing is selected
          if (x >= viewportMinX && x <= viewportMaxX
              && y >= viewportMaxY && y <= viewportMinY) {
            CurvePoint p = viewToWorld(new CurvePoint(x, y));
            curve.add(1, p);

            sortPoints();
            repaint();
          }
        }
      }
    }

    /**
     * Convert given control point from world to viewport coordinates
     *
     * @param in The point to convert 
     * @return A new control point representing the point in view space
     */
    private CurvePoint worldToView(CurvePoint in) {
      float sx = (viewportMaxX - viewportMinX) / (worldMaxX - worldMinX);
      float sy = (viewportMaxY - viewportMinY) / (worldMaxY - worldMinY);

      float cx = -sx * worldMinX + viewportMinX;
      float cy = -sy * worldMinY + viewportMinY;

      return new CurvePoint(sx * in.x + cx, sy * in.y + cy);
    }

    /**
     * Convert the given point in view space into world space
     *
     * @param view The point to convert
     * @return A new control point that represent the point in world space
     */
    public CurvePoint viewToWorld(CurvePoint view) {
      float sx = (viewportMaxX - viewportMinX) / (worldMaxX - worldMinX);
      float sy = (viewportMaxY - viewportMinY) / (worldMaxY - worldMinY);

      float cx = -sx * worldMinX + viewportMinX;
      float cy = -sy * worldMinY + viewportMinY;

      return new CurvePoint((view.x - cx) / sx, (view.y - cy) / sy);
    }

    /**
     * Draw the legen of the graph
     *
     * @param g The graphics context on which to draw the legend
     * @param vx0 The view top-left x coordinate
     * @param vy0 The view top-left y coordinate
     * @param vx1 The view bottom-right x coordinate
     * @param vy1 The view bottom-right y coordinate
     */
    private void drawLegend(Graphics2D g, float vx0, float vy0, float vx1,
        float vy1) {
      g.setColor(COLOR_BACKGROUND);
      g.fillRect((int) vx0, (int) (vy1 - viewBorderY),
          (int) (vx1 - vx0 + viewBorderX),
          (int) (vy0 - vy1 + viewBorderY * 2));

      int legendLineMain = (int) viewBorderY;
      int legendLineMin = 8;

      g.setColor(COLOR_LEGEND_BACKGROUND);
      g.fillRect((int) vx0, (int) vy0, (int) (vx1 - vx0 + viewBorderX),
          (int) (vy0));

      // x line bottom (min y)
      g.setColor(COLOR_LEGEND);
      g.drawLine((int) vx0, (int) vy0, (int) (vx1 + viewBorderX),
          (int) vy0);
      g.drawLine((int) vx0, (int) vy0 + 1, (int) (vx1 + viewBorderX),
          (int) vy0 + 1);

      // let's first calculate how much space is available
      float space = vx1 - vx0;

      // now estimate that we need at least pixel per interval
      int intervalCountX = ((int) space / 50);
      if ((intervalCountX & 1) == 1)
        intervalCountX--;

      // x
      for (int x = 0; x < intervalCountX + 1; x++) {
        float xi0 = (worldMaxX - worldMinX) / intervalCountX
            * x;
        CurvePoint c = worldToView(new CurvePoint(xi0, 0));
        c.y = vy0;

        g.setColor(COLOR_LEGEND);
        g.drawLine((int) c.x, (int) c.y, (int) c.x, (int) c.y
            + legendLineMain);

        g.setColor(COLOR_LEGEND_GRID);
        g.drawLine((int) c.x, (int) (viewportMaxY - viewBorderY),
            (int) (c.x), (int) (viewportMinY));

        String text = convertFloat(xi0 * 1.0f);

        g.setColor(COLOR_LEGEND);
        g
            .drawString(text, (int) c.x + 2, (int) (c.y
                + viewBorderY - 2));

        if (x <= (intervalCountX - 1)) {
          for (int xsub = 0; xsub < 2; xsub++) {
            float xi1 = (worldMaxX - worldMinX)
                / intervalCountX * (x + 1);
            CurvePoint ci = worldToView(new CurvePoint((xi0 + xi1)
                / 2.0f * xsub, 0));
            ci.y = vy0;

            g.setColor(COLOR_LEGEND);
            g.drawLine((int) ci.x, (int) ci.y, (int) ci.x,
                (int) ci.y + legendLineMin);
          }
        }
      }

      // y
      g.setColor(COLOR_LEGEND_BACKGROUND);
      g.fillRect(0, (int) (vy1 - viewBorderY), (int) vx0,
          (int) (vy0 + viewBorderY));

      // let's first calculate how much space is available
      space = vy0 - vy1;

      // now estimate that we need at least pixel per interval
      int intervalCountY = ((int) space / 30);
      if ((intervalCountY & 1) == 1)
        intervalCountY--;

      // y
      int legendLineMainY = 50;
      for (int y = 0; y < intervalCountY + 1; y++) {
        float yi0 = (worldMaxY - worldMinY) / intervalCountY
            * y + worldMinY;
        CurvePoint c = worldToView(new CurvePoint(0, yi0));

        // legend line
        g.setColor(COLOR_LEGEND);
        g.drawLine((int) c.x - legendLineMainY, (int) c.y, (int) c.x,
            (int) c.y);

        // grid line
        g.setColor(COLOR_LEGEND_GRID);
        g.drawLine((int) c.x, (int) (c.y), (int) (c.x + viewportMaxX),
            (int) (c.y));

        // legend text
        String text = convertFloat(yi0);

        g.setColor(COLOR_LEGEND);
        g.drawString(text, (int) vx0
            - g.getFontMetrics().stringWidth(text) - 2,
            (int) (c.y - 2));
      }

      // x line top (max y)
      g.setColor(COLOR_LEGEND);
      g.drawLine((int) vx0, (int) (vy1), (int) (vx1 + viewBorderX),
          (int) (vy1));

      // left
      g.drawLine((int) vx0, (int) vy0, (int) vx0,
          (int) (vy1 - viewBorderY));

      // right
      g.drawLine((int) vx1, (int) vy0, (int) vx1,
          (int) (vy1 - viewBorderY));
    }

    /**
     * Convert the list of the given CurvePoint
     *
     * @param curve The list of points to convert
     * @return The new list of points in Point2D format
     */
    private ArrayList convertToPoint2DCurve(ArrayList curve) {
      ArrayList bla = new ArrayList();
      for (int j = 0; j < curve.size(); j++) {
        CurvePoint c = (CurvePoint) curve.get(j);
        bla.add(new Vector2f(c.getX(), c.getY()));
      }
      return bla;
    }

    /**
     * Convert a point 2d curve into a curve point curve
     *
     * @param point2DCurve The list of points to convert
     * @return The list of points in CurvePoint format
     */
    private ArrayList convertToCurvePointCurve(ArrayList point2DCurve) {
      ArrayList curvePointCurve = new ArrayList();
      for (int j = 0; j < point2DCurve.size(); j++) {
        Vector2f c = (Vector2f) point2DCurve.get(j);
        curvePointCurve.add(new CurvePoint(c.getX(), c.getY()));
      }
      return curvePointCurve;
    }

    /**
     * Paint the display
     *
     * @param g The graphics context to draw onto
     * @param vx0 The top-left x coordinate
     * @param vy0 The top-left y coordinate
     * @param vx1 The bottom-right x coordinate
     * @param vy1 The bottom-right y coordinate
     */
    public void paint(Graphics2D g, float vx0, float vy0, float vx1, float vy1) {
      if (!isActive()) {
        g.drawImage(backgroundImage, 0, (int) vy1
            - backgroundImage.getHeight(), null);
        return;
      }

      viewportMinX = vx0 + viewBorderX;
      viewportMaxX = vx1 - viewBorderX;
      viewportMinY = vy1 - viewBorderY;
      viewportMaxY = vy0 + viewBorderY;

      drawLegend(g, viewportMinX, viewportMinY, viewportMaxX,
          viewportMaxY);

      g.setColor(COLOR_LEGEND_GRID);
      g.drawLine((int) vx0, (int) vy0, (int) (vx1), (int) vy0);

      int[] xPoints = new int[curve.size()];
      int[] yPoints = new int[curve.size()];

      for (int i = 0; i < curve.size(); i++) {
        CurvePoint p = worldToView((CurvePoint) curve.get(i));
        xPoints[i] = (int) (p.x);
        yPoints[i] = (int) (p.y);
      }

      g.setColor(COLOR_LINE);
      g.drawPolyline(xPoints, yPoints, curve.size());

      int width = 6;
      int height = 6;
      for (int i = 0; i < curve.size(); i++) {
        Color color;
        Color colorOutline;
        int off;

        if (((CurvePoint) curve.get(i)).selected) {
          color = COLOR_SELECTED_POINT;
          colorOutline = COLOR_SELECTED_POINT_OUTLINE;
          off = 1;
        } else {
          color = COLOR_POINT;
          colorOutline = COLOR_POINT_OUTLINE;
          off = 0;
        }

        g.setColor(colorOutline);
        g.fillRect(xPoints[i] - width / 2 - off, yPoints[i] - height
            / 2 - off, width + off * 2, height + off * 2);

        g.setColor(color);
        g.fillRect(xPoints[i] - width / 2 - off + 1, yPoints[i]
            - height / 2 - off + 1, width + off * 2 - 2, height
            + off * 2 - 2);

        if (value != null && mouseX >= viewportMinX
            && mouseX <= viewportMaxX && mouseY >= vy0
            && mouseY <= vy1) {
          value.setCurve(convertToPoint2DCurve(curve));
          value.setMin((int) worldMinY);
          value.setMax((int) worldMaxY);

          // draw little cross where we are
          CurvePoint a = viewToWorld(new CurvePoint(mouseX, 0));
          float b = value.getValue(a.getX());

          CurvePoint crossPoint = new CurvePoint(a.getX(), b);
          CurvePoint p = worldToView(crossPoint);

          // draw cross-line where we are
          g.setColor(COLOR_LEGEND_GRID_CROSS);
          g.drawLine((int) p.getX(), (int) vy0, (int) p.getX(),
              (int) vy1);

          // update mouse position labels
          valueXLabel.setText(TEXT_CURRENT_X
              + convertFloat(crossPoint.getX()));
          valueYLabel.setText(TEXT_CURRENT_Y
              + convertFloat(crossPoint.getY()));

        }
      }
    }

    /**
     * Sort the control points based on their position
     */
    private void sortPoints() {
      final CurvePoint firstPt = (CurvePoint) curve.get(0);
      final CurvePoint lastPt = (CurvePoint) curve.get(curve.size() - 1);

      Comparator compare = new Comparator() {
        public int compare(Object firstO, Object secondO) {
          CurvePoint first = (CurvePoint) firstO;
          CurvePoint second = (CurvePoint) secondO;

          if (first == firstPt) {
            return -1;
          }
          if (second == lastPt) {
            return -1;
          }

          if (first.x < second.x)
            return -1;
          else if (first.x > second.x)
            return 1;
          else
            return 0;
        }
      };

      Collections.sort(curve, compare);
    }

    /**
     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
     */
    public void paintComponent(Graphics g1d) {
      super.paintComponent(g1d);
      Graphics2D g = (Graphics2D) g1d;

      g.setColor(new Color(0x303040));
      g.fillRect(0, 0, this.getWidth(), this.getHeight());

      paint(g, 0, 0, this.getWidth(), this.getHeight());
    }

    /**
     * Check if this graph panel is currently being used
     *
     * @return True if the graph panel is current being used
      */
    private boolean isActive() {
      return (curve != null);
    }

    /**
     * Convert a float to a string format
     *
     * @param f The float to convert
     * @return The string formatted from the float
     */
    private String convertFloat(float f) {
      NumberFormat format = NumberFormat.getInstance();
      format.setMinimumFractionDigits(2);
      format.setMaximumFractionDigits(2);
      format.setMinimumIntegerDigits(1);
      format.setMaximumIntegerDigits(5);
      return format.format(f);
    }

    /**
     * A point on the curve
     *
     * @author void
     */
    private class CurvePoint {
      /** The x coordinate of the point */
      public float x;
      /** The y coordinate of the point */
      public float y;
      /** True if this point is selected */
      public boolean selected;

      /**
       * Create a new curve point
       *
       * @param x The x coordinate of the curve point
       * @param y The y coordinate of the curve point
       */
      public CurvePoint(float x, float y) {
        this.x = x;
        this.y = y;
        selected = false;
      }

      /**
       * Check if this point is selected
       *
       * @return True if the point is selected
       */
      public boolean isSelected() {
        return selected;
      }

      /**
       * Get the x coordinate of this point
       *
       * @return The x coordinate of this point
       */
      public float getX() {
        return x;
      }

      /**
       * Get the y coordinate of this point
       *
       * @return The y coordinate of this point
       */
      public float getY() {
        return y;
      }
    }

    /**
     * Get the world minimum y value
     *
     * @return The world minimum y value
     */
    public float getWorldMinY() {
      return worldMinY;
    }

    /**
     * Set the world minimum y value
     *
     * @param worldMinY The world minimum y value
     */
    public void setWorldMinY(float worldMinY) {
      this.worldMinY = worldMinY;
    }

    /**
     * Get the world maximum y value
     *
     * @return The world maximum y value
     */
    public float getWorldMaxY() {
      return worldMaxY;
    }

    /**
     * Set the world maximum y value
     *
     * @param worldMaxY The world maximum y value
     */
    public void setWorldMaxY(float worldMaxY) {
      this.worldMaxY = worldMaxY;
    }
  }

  /**
   * Simple test case for the gradient painter
   *
   * @param argv
   *            The arguments supplied at the command line
   */
  public static void main(String[] argv) {
    JFrame frame = new JFrame("Whiskas Gradient Editor");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel main = new JPanel();
    main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
    main.setBackground(Color.CYAN);
    frame.getContentPane().add(main);

    //
    GraphEditorWindow bottom = new GraphEditorWindow();

    ArrayList curve = new ArrayList();
    curve.add(new Vector2f(0.0f, 0.0f));
    curve.add(new Vector2f(1.0f, 255.0f));
    LinearInterpolator test = new ConfigurableEmitter("bla").new LinearInterpolator(
        curve, 0, 255);
    bottom.registerValue(test, "Test");

    curve = new ArrayList();
    curve.add(new Vector2f(0.0f, 255.0f));
    curve.add(new Vector2f(1.0f, 0.0f));
    test = new ConfigurableEmitter("bla").new LinearInterpolator(curve, 0,
        255);
    bottom.registerValue(test, "Test 2");

    main.add(bottom);

    frame.pack();
    frame.setVisible(true);
    frame.setSize(600, 300);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    frame.setVisible(true);
  }
}
TOP

Related Classes of org.newdawn.slick.tools.peditor.GraphEditorWindow$GraphPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.