package org.newdawn.slick.tools.peditor; import java.awt.Color; import java.awt.Component; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JFrame; import javax.swing.JPanel; /** * A generic editor for configuring a multiple point varying gradient * * @author kevin */ public class GradientEditor extends JPanel { /** The list of control points */ private ArrayList list = new ArrayList(); /** The current selcted control point */ private ControlPoint selected; /** The polygon used for the markers */ private Polygon poly = new Polygon(); /** A button to add a control point */ private JButton add = new JButton("Add"); /** A button to edit a control point */ private JButton edit = new JButton("Edit"); /** A button to delete a control point */ private JButton del = new JButton("Del"); /** The x position of the gradient bar */ private int x; /** The y position of the gradient bar */ private int y; /** The width of the gradient bar */ private int width; /** The height of the gradient bar */ private int barHeight; /** The listeners that should be notified of changes to this emitter */ private ArrayList listeners = new ArrayList(); /** * Create a new editor for gradients * */ public GradientEditor() { setLayout(null); add.setBounds(20,70,75,20); add(add); edit.setBounds(100,70,75,20); add(edit); del.setBounds(180,70,75,20); add(del); add.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addPoint(); } }); del.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { delPoint(); } }); edit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { editPoint(); } }); list.add(new ControlPoint(Color.white, 0)); list.add(new ControlPoint(Color.black, 1)); poly.addPoint(0, 0); poly.addPoint(5, 10); poly.addPoint(-5,10); this.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { selectPoint(e.getX(), e.getY()); repaint(0); if (e.getClickCount() == 2) { editPoint(); } } }); this.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent e) { movePoint(e.getX(), e.getY()); repaint(0); } public void mouseMoved(MouseEvent e) { } }); } /** * @see javax.swing.JComponent#setEnabled(boolean) */ public void setEnabled(boolean enabled) { super.setEnabled(enabled); Component[] components = getComponents(); for (int i=0;i<components.length;i++) { components[i].setEnabled(enabled); } } /** * Add a listener that will be notified on change of this editor * * @param listener The listener to be notified on change of this editor */ public void addActionListener(ActionListener listener) { listeners.add(listener); } /** * Remove a listener from this editor. It will no longer be notified * * @param listener The listener to be removed */ public void removeActionListener(ActionListener listener) { listeners.remove(listener); } /** * Fire an update to all listeners */ private void fireUpdate() { ActionEvent event = new ActionEvent(this,0,""); for (int i=0;i<listeners.size();i++) { ((ActionListener) listeners.get(i)).actionPerformed(event); } } /** * Check if there is a control point at the specified mouse location * * @param mx The mouse x coordinate * @param my The mouse y coordinate * @param pt The point to check agianst * @return True if the mouse point conincides with the control point */ private boolean checkPoint(int mx, int my, ControlPoint pt) { int dx = (int) Math.abs((10+(width * pt.pos)) - mx); int dy = Math.abs((y+barHeight+7)-my); if ((dx < 5) && (dy < 7)) { return true; } return false; } /** * Add a new control point */ private void addPoint() { ControlPoint point = new ControlPoint(Color.white, 0.5f); for (int i=0;i<list.size()-1;i++) { ControlPoint now = (ControlPoint) list.get(i); ControlPoint next = (ControlPoint) list.get(i+1); if ((now.pos <= 0.5f) && (next.pos >=0.5f)) { list.add(i+1,point); break; } } selected = point; sortPoints(); repaint(0); fireUpdate(); } /** * Sort the control points based on their position */ private void sortPoints() { final ControlPoint firstPt = (ControlPoint)list.get(0); final ControlPoint lastPt = (ControlPoint)list.get(list.size()-1); Comparator compare = new Comparator() { public int compare(Object first, Object second) { if (first == firstPt) { return -1; } if (second == lastPt) { return -1; } float a = ((ControlPoint) first).pos; float b = ((ControlPoint) second).pos; return (int) ((a-b) * 10000); } }; Collections.sort(list, compare); } /** * Edit the currently selected control point * */ private void editPoint() { if (selected == null) { return; } Color col = JColorChooser.showDialog(this, "Select Color", selected.col); if (col != null) { selected.col = col; repaint(0); fireUpdate(); } } /** * Select the control point at the specified mouse coordinate * * @param mx The mouse x coordinate * @param my The mouse y coordinate */ private void selectPoint(int mx, int my) { if (!isEnabled()) { return; } for (int i=1;i<list.size()-1;i++) { if (checkPoint(mx,my,(ControlPoint) list.get(i))) { selected = (ControlPoint) list.get(i); return; } } if (checkPoint(mx,my,(ControlPoint) list.get(0))) { selected = (ControlPoint) list.get(0); return; } if (checkPoint(mx,my,(ControlPoint) list.get(list.size()-1))) { selected = (ControlPoint) list.get(list.size()-1); return; } selected = null; } /** * Delete the currently selected point */ private void delPoint() { if (!isEnabled()) { return; } if (selected == null) { return; } if (list.indexOf(selected) == 0) { return; } if (list.indexOf(selected) == list.size()-1) { return; } list.remove(selected); sortPoints(); repaint(0); fireUpdate(); } /** * Move the current point to the specified mouse location * * @param mx The x coordinate of the mouse * @param my The y coordinate of teh mouse */ private void movePoint(int mx, int my) { if (!isEnabled()) { return; } if (selected == null) { return; } if (list.indexOf(selected) == 0) { return; } if (list.indexOf(selected) == list.size()-1) { return; } float newPos = (mx - 10) / (float) width; newPos = Math.min(1, newPos); newPos = Math.max(0, newPos); selected.pos = newPos; sortPoints(); fireUpdate(); } /** * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ public void paintComponent(Graphics g1d) { super.paintComponent(g1d); Graphics2D g = (Graphics2D) g1d; width = getWidth() - 30; x = 10; y = 20; barHeight = 25; for (int i=0;i<list.size()-1;i++) { ControlPoint now = (ControlPoint) list.get(i); ControlPoint next = (ControlPoint) list.get(i+1); int size = (int) ((next.pos - now.pos) * width); g.setPaint(new GradientPaint(x,y,now.col,x+size,y,next.col)); g.fillRect(x,y,size+1,barHeight); x += size; } g.setColor(Color.black); g.drawRect(10,y,width,barHeight-1); for (int i=0;i<list.size();i++) { ControlPoint pt = (ControlPoint) list.get(i); g.translate(10+(width * pt.pos),y+barHeight); g.setColor(pt.col); g.fillPolygon(poly); g.setColor(Color.black); g.drawPolygon(poly); if (pt == selected) { g.drawLine(-5, 12, 5, 12); } g.translate(-10-(width * pt.pos),-y-barHeight); } } /** * Add a control point to the gradient * * @param pos The position in the gradient (0 -> 1) * @param col The color at the new control point */ public void addPoint(float pos, Color col) { ControlPoint point = new ControlPoint(col, pos); for (int i=0;i<list.size()-1;i++) { ControlPoint now = (ControlPoint) list.get(i); ControlPoint next = (ControlPoint) list.get(i+1); if ((now.pos <= 0.5f) && (next.pos >=0.5f)) { list.add(i+1,point); break; } } repaint(0); } /** * Set the starting colour * * @param col The color at the start of the gradient */ public void setStart(Color col) { ((ControlPoint) list.get(0)).col = col; repaint(0); } /** * Set the ending colour * * @param col The color at the end of the gradient */ public void setEnd(Color col) { ((ControlPoint) list.get(list.size()-1)).col = col; repaint(0); } /** * Remove all the control points from the gradient editor (this does * not include start and end points) */ public void clearPoints() { for (int i=1;i<list.size()-1;i++) { list.remove(1); } repaint(0); fireUpdate(); } /** * Get the number of control points in the gradient * * @return The number of control points in the gradient */ public int getControlPointCount() { return list.size(); } /** * Get the graident position of the control point at the specified * index. * * @param index The index of the control point * @return The graident position of the control point */ public float getPointPos(int index) { return ((ControlPoint) list.get(index)).pos; } /** * Get the color of the control point at the specified * index. * * @param index The index of the control point * @return The color of the control point */ public Color getColor(int index) { return ((ControlPoint) list.get(index)).col; } /** * A control point defining the gradient * * @author kevin */ public class ControlPoint { /** The color at this control point */ public Color col; /** The position of this control point (0 -> 1) */ public float pos; /** * Create a new control point * * @param col The color at this control point * @param pos The position of this control point (0 -> 1) */ private ControlPoint(Color col, float pos) { this.col = col; this.pos = pos; } } /** * 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(); JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createTitledBorder("Gradient")); panel.setLayout(null); frame.setContentPane(panel); GradientEditor editor = new GradientEditor(); editor.setBounds(10,15,270,100); panel.add(editor); frame.setSize(300,200); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } }