Computer Science 252
Problem Solving with Java

Spring 2014, The College of Saint Rose

RecScribbler Demo

A working demo of RecScribbler will appear below. Click inside the applet to interact with it.



RecScribbler BlueJ Project

Click here to download a BlueJ project for RecScribbler.


RecScribbler Source Code

The Java source code for RecScribbler is below. Click on a file name to download it.


RecScribbler.java

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JPanel;
import objectdraw.*;

/*
 * This program is another step toward a drawing program that will 
 * be much more functional than our simple Scribble example.
 * Here, we construct a recursive data structure to represent
 * a Scribble, and can move all of the Scribbles which are 
 * stored in another recursive structure.  We also added
 * setColor and clear capabilities.
 *
 * Jim Teresco, CSC 252, The College of Saint Rose, Fall 2013
 * Based on similar example from Williams College CS 134.
 * 
 * $Id: RecScribbler.java 2249 2013-11-07 16:20:52Z terescoj $
 */

public class RecScribbler extends WindowController
    implements ActionListener {

    // user modes
    // using ints rather than boolean to allow for extension to
    // other modes
    private static final int DRAWING = 1;
    private static final int MOVING = 2;
    private static final int COLORING = 3;

    // the current scribble
    private Scribble currentScribble;
    
    // the list of all Scribble objects
    private ScribbleList allScribbles;

    // stores last point for drawing or dragging
    private Location lastPoint;

    //  the scribble that has been selected for moving, if any
    // is null if not
    private Scribble draggingScribble;
    
    // the scribble we selected for other actions (coloring)
    private Scribble selectedScribble;

    // buttons that allow user to select modes
    private JButton setDraw, setMove, setColor, clearButton;

    // the current mode -- drawing by default
    private int chosenAction = DRAWING;
    
    // our Random
    private Random r;

    public void begin() {
        // create the user interface components
        Container contentPane = getContentPane();
        setDraw = new JButton("Draw");
        setMove = new JButton("Move");
        setColor = new JButton("Set Color");
        clearButton = new JButton("Clear");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(setDraw);
        buttonPanel.add(setMove);
        buttonPanel.add(setColor);
        buttonPanel.add(clearButton);

        contentPane.add(buttonPanel, BorderLayout.SOUTH);

        // add listeners
        setDraw.addActionListener(this);
        setMove.addActionListener(this);
        setColor.addActionListener(this);
        clearButton.addActionListener(this);
        
        contentPane.validate();
        
        // make the current scribble empty
        currentScribble = new Scribble(null, null);
        
        // create our empty list
        allScribbles = new ScribbleList(null, null);
        
        // not dragging to start
        draggingScribble = null;
        
        // set up random
        r = new Random();
    }


    public void onMousePress(Location point) {
        if (chosenAction == DRAWING) {
            // start a new (empty) scribble for drawing
            currentScribble = new Scribble(null, null);
        } 
        else if (chosenAction == MOVING) {
            // check if user clicked on current scribble
            draggingScribble = allScribbles.whichContains(point);
        }
        else if (chosenAction == COLORING) {
            // find which one contains the point, if any
            selectedScribble = allScribbles.whichContains(point);
            if (selectedScribble != null) {
                Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
                selectedScribble.setColor(c);
            }
        }
        // remember point of press for drawing or moving
        lastPoint = point;
    }



    public void onMouseDrag(Location point) {
        if (chosenAction == DRAWING) {
            // add line segment to current scribble
            currentScribble =
            new Scribble(new Line(lastPoint, point, canvas),
                currentScribble);
        } else if (chosenAction == MOVING) {
            // move current scribble if dragging it
            if (draggingScribble != null) {
                draggingScribble.move(point.getX() - lastPoint.getX(),
                    point.getY() - lastPoint.getY());
            }
        }
        // update for next move or draw
        lastPoint = point;
    }

    public void onMouseRelease(Location point) {
        
        if (chosenAction == DRAWING) {
            allScribbles = new ScribbleList(currentScribble, allScribbles);
        }
        
        draggingScribble = null;
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == setDraw) {
            chosenAction = DRAWING;
        }
        else if (e.getSource() == setMove) {
            chosenAction = MOVING;
        }
        else if (e.getSource() == setColor) {
            chosenAction = COLORING;
        }
        else if (e.getSource() == clearButton) {
            // clear the canvas
            canvas.clear();
            // replace our ScribbleList with an empty one
            allScribbles = new ScribbleList(null, null);
        }
    }
}

Scribble.java

import java.awt.*;
import objectdraw.*;

/*
 * A very basic recursive data structure to represent
 * a Scribble, augmented with contains, move, and isEmpty
 * methods.  Now with setColor!
 *
 * Jim Teresco, CSC 252, The College of Saint Rose, Fall 2013
 * Based on similar example from Williams College CS 134.
 * 
 * $Id: Scribble.java 2249 2013-11-07 16:20:52Z terescoj $
 */

// A class to represent a scribble
public class Scribble {
    private Line first;           // an edge line of the scribble
    private Scribble rest;        // the rest of the scribble

    // Our constructor here doesn't actually do any of the
    // drawing - it takes a line that someone else created and
    // which is supposed to be part of the Scribble, and
    // a reference to another Scribble which represents
    // any previous Scribble.
    public Scribble(Line segment, Scribble theRest) {
        first = segment;
        rest = theRest;
    }

    // returns true iff the scribble contains the point
    // Note that things are slightly more complex than some
    // of our other recursive accessors as there are three
    // possibilities: 1) this Scribble is empty, in which
    // case it cannot contain the point, 2) first contains
    // the point, in which case the whole Scribble contains
    // the point, or 3) the answer depends on whether rest
    // (itself a Scribble, hence the recursive call) contains
    // the point
    public boolean contains(Location point) {
        if (isEmpty()) {
            return false;
        } else if (first.contains(point)) {
            return true;
        } else {
            return rest.contains(point);
        }
    }



    // the scribble is moved xOffset in the x direction
    //    and yOffset in the y direction
    public void move(double xOffset, double yOffset) {
        if (!isEmpty()) {
            first.move(xOffset, yOffset);
            rest.move(xOffset, yOffset);
        }
    }

    // returns true iff the list is empty
    public boolean isEmpty() {
        return (first == null);
    }
    
    // set the color of this Scribble
    public void setColor(Color c) {
        
        if (!isEmpty()) {
            first.setColor(c);
            rest.setColor(c);
        }
    }
}



ScribbleList.java


/**
 * A list of Scribbles!
 * 
 * @author Jim Teresco and CSC 252 class, Fall 2013 
 */

import objectdraw.*;
import java.awt.*;

public class ScribbleList {

    private Scribble first;
    private ScribbleList rest;
    
    public ScribbleList(Scribble first, ScribbleList rest){
    
        this.first = first;
        this.rest = rest;
    }

    // return the Scribble in the list that contains the given point
    // and null if no Scribble contains the point
    public Scribble whichContains(Location point) {
        
        // an empty ScribbleList can't have a Scribble
        // that contains the point
        if (first == null) return null;
        
        // does the first Scribble contain the point?
        if (first.contains(point)) return first;
        
        return rest.whichContains(point);
    }
}