package ika.gui; import ika.utils.CatmullRomSpline; import ika.utils.GraphicsUtils; import java.awt.Color; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.GeneralPath; import javax.swing.JComponent; public class GradationGraph extends JComponent implements MouseListener, MouseMotionListener, KeyListener { public static final String CURVE_CHANGED = "curve changed"; public static final String SELECTION_CHANGED = "selection changed"; private static final Color EXTRA_LIGHT_GRAY = new Color(220, 220, 220); private static final int GRADIENT_BAR_WIDTH = 5; private static final int HANLDE_SIZE = 5; private CatmullRomSpline[] curves; private CatmullRomSpline curve; private int whichCurve = 0; private int selected = -1; private boolean showFirstCurveOnly = true; private boolean showGradientBars = true; private boolean showDiagonal = true; private int[] histogram = null; private int histogramHighlight = -1; private String label; public GradationGraph() { addMouseListener(this); addKeyListener(this); setCurves(new CatmullRomSpline[]{new CatmullRomSpline(), new CatmullRomSpline(), new CatmullRomSpline()}); } @Override public Dimension getMinimumSize() { return new Dimension(257 + GRADIENT_BAR_WIDTH, 257 + GRADIENT_BAR_WIDTH); } @Override public Dimension getPreferredSize() { return new Dimension(257 + GRADIENT_BAR_WIDTH, 257 + GRADIENT_BAR_WIDTH); } public void setCurves(CatmullRomSpline[] curves) { this.curves = curves; if (whichCurve > curves.length) { whichCurve = 0; } curve = curves[whichCurve]; firePropertyChange(CURVE_CHANGED, null, null); repaint(); } public void setCurve(CatmullRomSpline curve) { this.setCurves(new CatmullRomSpline[]{curve}); } public CatmullRomSpline getCurve(int i) { return this.curves[i]; } public void setWhichCurve(int which) { whichCurve = which; if (whichCurve == -1) { whichCurve = 0; showFirstCurveOnly = true; } else { showFirstCurveOnly = false; } if (curves != null) { curve = curves[whichCurve]; repaint(); } } protected void paintLabel(Graphics2D g2d) { g2d.setColor(Color.DARK_GRAY); g2d.addRenderingHints(GraphicsUtils.antialiasedTextHints); Dimension size = this.getSize(); ika.utils.CenteredStringRenderer.drawCentered(g2d, this.label, size.width / 2, (int)(size.height * 0.4), ika.utils.CenteredStringRenderer.NOFLIP); } protected void paintHistogram(Graphics2D g) { if (histogram == null) { return; } Color histoColor = isEnabled() ? Color.lightGray : EXTRA_LIGHT_GRAY; Color highlightColor = isEnabled() ? Color.BLACK : Color.LIGHT_GRAY; g.setColor(histoColor); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); for (int i = 0; i < histogram.length; i++) { if (i == histogramHighlight) { g.setColor(highlightColor); g.drawLine(i, 255 - Math.max(1, histogram[i]), i, 255); g.setColor(histoColor); } else { g.drawLine(i, 255 - histogram[i], i, 255); } } } protected void paintGrid(Graphics2D g) { g.setColor(isEnabled() ? Color.lightGray : EXTRA_LIGHT_GRAY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); g.drawLine(0, 64, 255, 64); g.drawLine(0, 128, 255, 128); g.drawLine(0, 191, 255, 191); g.drawLine(64, 0, 64, 255); g.drawLine(128, 0, 128, 255); g.drawLine(191, 0, 191, 255); } protected void paintHandles(Graphics2D g, CatmullRomSpline curve) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); for (int i = 0; i < curve.x.length; i++) { int x = (int) (255 * curve.x[i]) + 1; int y = 255 - (int) (255 * curve.y[i]) + 1; //g.setColor(color); //g.fillRect(x - HANLDE_SIZE / 2, y - HANLDE_SIZE / 2, HANLDE_SIZE, HANLDE_SIZE); g.setColor(isEnabled() ? Color.BLACK : Color.LIGHT_GRAY); g.fillRect(x - HANLDE_SIZE / 2, y - HANLDE_SIZE / 2, HANLDE_SIZE, HANLDE_SIZE); } } protected void paintCurve(Graphics2D g, CatmullRomSpline curve, Color color) { GeneralPath p = new GeneralPath(); int numKnots = curve.x.length; float[] nx = new float[numKnots + 2]; float[] ny = new float[numKnots + 2]; System.arraycopy(curve.x, 0, nx, 1, numKnots); System.arraycopy(curve.y, 0, ny, 1, numKnots); nx[0] = nx[1]; ny[0] = ny[1]; nx[numKnots + 1] = nx[numKnots]; ny[numKnots + 1] = ny[numKnots]; g.setColor(color); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int x = 1; x <= 255; x++) { int y = 256 - (int) (255 * curve.evaluateSimilarToPrevious(x / 255f)); x = x < 0 ? 0 : x > 255 ? 255 : x; y = y < 0 ? 0 : y > 255 ? 255 : y; if (x == 1) { p.moveTo(x, y); } else { p.lineTo(x, y); } } g.draw(p); } private void paintGradientBars(Graphics2D g2d) { if (!showGradientBars) { return; } Color darkColor = isEnabled() ? Color.BLACK : Color.GRAY; // vertical bar GradientPaint vGrad = new GradientPaint(0, 1, Color.WHITE, 0, 255, darkColor); g2d.setPaint(vGrad); g2d.fillRect(0, 1, GRADIENT_BAR_WIDTH, 255); // horizontal bar int x1 = 1 + GRADIENT_BAR_WIDTH; int x2 = 1 + GRADIENT_BAR_WIDTH + 255; GradientPaint hGrad = new GradientPaint(x1, 0, darkColor, x2, 0, Color.WHITE); g2d.setPaint(hGrad); g2d.fillRect(x1, 256, 255, GRADIENT_BAR_WIDTH); } @Override public void paintComponent(Graphics g) { if (curves == null) { return; } Graphics2D g2d = (Graphics2D) g.create(); //copy g. Recomended by Sun tutorial. try { paintGradientBars(g2d); g2d.translate(GRADIENT_BAR_WIDTH, 0); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); // paint background g.setColor(Color.white); g.fillRect(1 + GRADIENT_BAR_WIDTH, 1, 255, 255); // draw oblique baseline if (showDiagonal) { g.setColor(isEnabled() ? Color.lightGray : EXTRA_LIGHT_GRAY); g.drawLine(1 + GRADIENT_BAR_WIDTH, 255, 255 + GRADIENT_BAR_WIDTH, 1); } paintGrid(g2d); // draw frame g.setColor(isEnabled() ? Color.black : Color.LIGHT_GRAY); g.drawRect(GRADIENT_BAR_WIDTH, 0, 255, 255); paintHistogram(g2d); paintHandles(g2d, curves[whichCurve]); Color grayCurveColor = isEnabled() ? Color.BLACK : EXTRA_LIGHT_GRAY; paintCurve(g2d, curves[0], showFirstCurveOnly ? grayCurveColor : Color.red); if (!showFirstCurveOnly && curves.length == 3) { paintCurve(g2d, curves[1], Color.green); paintCurve(g2d, curves[2], Color.blue); } paintLabel(g2d); } finally { g2d.dispose(); //release the copy's resources. Recomended by Sun tutorial. } } @Override public void mousePressed(MouseEvent e) { if (!isEnabled()) { return; } requestFocus(); int x = e.getX() - 1 - GRADIENT_BAR_WIDTH; int y = e.getY() - 1; int newSelected = -1; for (int i = 0; i < curve.x.length; i++) { int kx = (int) (255 * curve.x[i]); int ky = 255 - (int) (255 * curve.y[i]) + 1; if (Math.abs(x - kx) < 5 && Math.abs(y - ky) < 5) { newSelected = i; addMouseMotionListener(this); break; } } if (newSelected != selected) { selected = newSelected; repaint(); } if (newSelected == -1) { selected = curve.addKnot(x / 255.0f, 1 - y / 255.0f); addMouseMotionListener(this); firePropertyChange(SELECTION_CHANGED, null, null); repaint(); } } @Override public void mouseReleased(MouseEvent e) { if (!isEnabled()) { return; } addMouseMotionListener(this); if (selected != -1) { int x = e.getX() - 1 - GRADIENT_BAR_WIDTH; int y = e.getY() - 1; if (selected != 0 && selected != curve.x.length - 1 && (x < 0 || x >= getWidth() || y < 0 || y > getHeight())) { curve.removeKnot(selected); repaint(); } firePropertyChange(CURVE_CHANGED, null, null); selected = -1; } } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { if (!isEnabled()) { return; } if (selected != -1) { int x = e.getX() - 1 - GRADIENT_BAR_WIDTH; int y = e.getY() - 1; x = (x < 0) ? 0 : (x > 255) ? 255 : x; y = (y < 0) ? 0 : (y > 255) ? 255 : y; float fx = x / 255.0f; float fy = 1 - y / 255.0f; if (selected > 0) { if (fx < curve.x[selected - 1]) { fx = curve.x[selected - 1]; } } else { fx = 0; } if (selected < curve.x.length - 1) { if (fx > curve.x[selected + 1]) { fx = curve.x[selected + 1]; } } else { fx = 1; } curve.x[selected] = fx; curve.y[selected] = fy; repaint(); } } @Override public void keyPressed(KeyEvent e) { if (!isEnabled()) { return; } switch (e.getKeyChar()) { case '1': case '2': case '3': setWhichCurve(e.getKeyChar() - '1'); break; } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } void setHistogram(int[] histogram) { this.histogram = histogram; this.repaint(); } /** * @param histogramHighlight the histogramHighlight to set */ public void setHistogramHighlight(int histogramHighlight) { this.histogramHighlight = histogramHighlight; this.repaint(); } /** * @return the label */ public String getLabel() { return label; } /** * @param label the label to set */ public void setLabel(String label) { this.label = label; } /** * @return the showGradientBars */ public boolean isShowGradientBars() { return showGradientBars; } /** * @param showGradientBars the showGradientBars to set */ public void setShowGradientBars(boolean showGradientBars) { this.showGradientBars = showGradientBars; this.repaint(); } /** * @return the showDiagonal */ public boolean isShowDiagonal() { return showDiagonal; } /** * @param showDiagonal the showDiagonal to set */ public void setShowDiagonal(boolean showDiagonal) { this.showDiagonal = showDiagonal; this.repaint(); } }