// Create and display a dragon curve using the mouse and keyboard.
// CS 310, Spring 2008

import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;



class MKDragonFrame
extends JFrame {

  MKDragonFrame(int height, int width) {

    // Create a dragon frame based on the given dragon curve with the given
    // dimensions.

    setTitle("Dragon Curve");
    setSize(height, width);
    add(new MKDragonPanel());
    }

  private static final long serialVersionUID = 0;
  }


class MKDragonPanel
extends JPanel {

  MKDragonPanel() {

    // Create a new panel that displays the given dragon curve.

    super();

    addMouseListener(new MouseHandler());
    addKeyListener(new KeyHandler());
    setFocusable(true);

    points = new ArrayList<Point2D> ();
    }


  private void
  drawDragonCurve(Graphics g) {

    // Draw to the given graphics context the current dragon curve.

    super.paintComponent(g);
    final Graphics2D g2 = (Graphics2D) g;
    dragonCurve.lineSegmentIterate(
      new DragonCurve.LineSegmentIterator() {
        public void
	doLineSegment(Point2D p1, Point2D p2) {
	  g2.draw(new Line2D.Float(p1, p2));
	  }
        });
    }

  private void
  drawLineSegments(Graphics g) {

    // Draw to the given graphics context the line segements for the new dragon
    // curve collected so far.

    if (points.size() == 1)
      super.paintComponent(g);

    for (int i = points.size() - 1; i > 0; i--) {
      final Point2D
	  p1 = points.get(i),
	  p2 = points.get(i - 1);

      g.drawLine((int) p1.getX(), (int) p1.getY(), 
		 (int) p2.getX(), (int) p2.getY());
      }
    }


  public void
  paintComponent(Graphics g) {

    // Draw to the given graphics context either the current dragon curve if
    // defined or else the chain for the new dragon curve collected so far.

    if (dragonCurve != null)
      drawDragonCurve(g);
    else
      drawLineSegments(g);
    }

  // The current dragon curve; it's the one being diplayed.

  private DragonCurve dragonCurve = null;

  // The points making up what will become the new current dragon curve.

  private final ArrayList<Point2D> points;

  private static final long serialVersionUID = 0;


  // What to do with mouse events.

  private 
  class MouseHandler
  implements MouseListener {

    public void mouseClicked(MouseEvent e) {

      // Take the location of the given mouse event as a new point on what will
      // become the new dragon curve.

      dragonCurve = null;
      points.add(new Point2D.Float(e.getX(), e.getY()));
      repaint();
      }

    public void mouseEntered(MouseEvent e) {
      }

    public void mouseExited(MouseEvent e) {
      }

    public void mousePressed(MouseEvent e) {
      }

    public void mouseReleased(MouseEvent e) {
      }
    }


  // What to do with keyboard events.

  private 
  class KeyHandler
  implements KeyListener {

    public void keyPressed(KeyEvent e) {
      }

    public void keyReleased(KeyEvent e) {
      }


    public void keyTyped(KeyEvent e) {

      // Show the current dragon curve at the order given by the key event.

      if (dragonCurve == null) {
	dragonCurve = new DragonCurve(points.toArray(new Point2D [] {}));
	points.clear();
        }

      final int order = Character.digit(e.getKeyChar(), 16);
      if (order > -1) {
        orderCurve(order);
        repaint();
        }
      }


    private void
    orderCurve(int order) {

      // Grow or regress the current dragon curve until it matches the given
      // order.

      while (dragonCurve.order() > order)
	dragonCurve = dragonCurve.parent();
      while (dragonCurve.order() < order)
	dragonCurve = dragonCurve.child();
      }
    }
  }


class 
MKDCShow {

  public static void 
  main(String args[]) {

    // Create a new dragon-display frame.

    MKDragonFrame frame = new MKDragonFrame(200, 200);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    }
  }

syntax highlighted by Code2HTML, v. 0.9.1