HOMEWORK 5: More Animation and Physics

This is an INDIVIDUAL assignment.

Objective

In this final assignment we'll look at animation, in particular how to add more realistic physical effects to the interface. In this project, we'll focus on the content area, adding an at-a-glance view of all pages (in the style of Apple's Exposé system).

The learning goals for this assignment are:

Description

In this homework we'll implement a nifty feature that allows the user to browse through pages in ways beyond simply the "next" and "previous" buttons.

We will provide a way for the user to zoom out of the current page in the content area, to see all the pages in the journal, and select one to zoom back in to it. This will work much like the Exposé feature in the Mac OS X interface (see here if you're unfamiliar with this feature).

Page Overview (Exposé) mode

You'll need to add a new button to the application to kick you into Overview Mode. When the user clicks this button the content area is animated so that the user is presented with an overview of all of the current pages in the journal. The effect should be a zoom out, with good animation principles applied (so, slow start, fast in the middle, slow stop, with a bit of anticipation/follow-through "jiggle" at the ends--be careful not to overdo it though). The page overview should present the user with shrunken thumbnail representations of all of the pages, arrayed in a grid. The pages should be scaled appropriately so that they roughly fill the overview, no matter how many pages the user has (so, if there are lots of pages, you will have really small thumbnails).

When the user clicks one of these pages, a reverse animation should be done that zooms you in to the selected page, which then works normally again.

Sweating the details is important in an animation like this. Remember that one of the uses of animation is to allow the user to maintain a sense of context during a change in the interface. Because of this, you want to ensure that there's consistency between the page that's being viewed when the transition starts, and where that page ends up when the transition finishes: as the currently viewed page begins to shrink during the switch into page overview mode, it should shrink *into* its final position in the grid so that the user can follow it visually.

Basic Architecture

There are a lot of possible ways to implement this assignment. Here's one way that seems fairly straightforward to me; let me know if you find a different/better way to do it.

Start by creating a new component that will act as a container (parent) for all of the individual page components in your application. As a container, this component will have references to all of the individual page components contained within it (and so can selectively render them, pass tweaked Graphics objects to them, etc.). In the "default" mode, this container will display only the current page--much like a container with CardLayout will only show one component at a time. (Start by making sure that introducing this new parent doesn't "break" anything: displaying a single page, resizing, doing next/prev/delete should all still work before you continue.)

When Overview Mode is activated, the desired visual effect is that the container should cycle through an animation that zooms out, rendering all of the pages as they shrink and move into their final positions in the grid. You might consider doing this by setting an "overview mode" flag in the container that tells it not to paint "normally," and then spinning off an updater thread that periodically updates whatever variables need to be updated as you cycle through the animation. Override your paintChildren() method to look at these variables to determine which mode it's in and how far it is through the animation. To render the thumbnails, I'd suggest creating a Graphics2D object that's scaled with the current value (you can call scale() on the Graphics2D object), and then iterate over each of the child page components, passing the Graphics2D object to their paint() method to have them each draw themselves.

Listen for mouse clicks in the container to figure out when a click is made; translate that to the bounds of the shrunken pages in the grid, and then start the animation to bring the selected page to the foreground. After this zoom-out transition, you can go back to the "default" mode where you just show the one current page. Note that while in the zoomed out view, page components don't need to be responsive to drawing or text input or any of the normal things they do when they're filling the screen.

Hint: Since you're essentially controlling the layout (size and position) of the child page components explicitly, you'll want to make sure that you turn off the LayoutManager for your container by setting it to null, since you don't want to be competing with it for how to set the children's layout.

Hint: For the basic container architecture, I'd suggest starting by subclassing JComponent. Any time your application creates a new page component, it should call add() to add it to the container's list of children (note that this is the *same* method that normally gets called to add children to *any* component).

Hint: Having repaint problems? Are your changes not getting reflected on screen? Be sure to call revalidate() anytime the set of children changes, or your size changes.

Extra Credit

As usual, there are a lot of ways you might make this assignment much fancier than described:

Deliverable

This is an INDIVIDUAL assignment; while you may ask others for help on Java or Swing details, please build your application on your own.

Here are the details for how to turn in the assignment. We'll be using this structure for all of the turn-ins:

1. Create an executable JAR file named courier.jar that contains your runnable application. (See here for details on how to create executable JAR files.) We should be able to run your program by typing "java -jar courier.jar" on the command line; please be sure that your application runs correctly using ONLY this command, and that it doesn't require any additional CLASSPATH or other environment variables, no additional parameters, no classfiles or images located outside the JAR file, etc.

2. Create a new directory using your last name as the name of the directory.

3. Put the courier.jar file into the top level of this directory, and all of your source files into a "source" subdirectory inside this directory.

4. Put a README.txt file into the top level of this directory. This file should contain your name and email address, the version of Java you used (Java 1.6.x only, please) as well as any special info we might need to know about your program (let us know if you did extra credit, for example).

5. ZIP this directory and submit via T-Square (instructions are here).

Please take care to remove any platform dependencies, such as hardcoded Windows path names or dependence on a particular look-and-feel that may not exist on all platforms. Also, if you use any images in your application, please make sure that you include these in your JAR file and that your code will refer to them and load them properly when they're in this JAR file (see this page for some details on how to include and load images from within a JAR file).

Grading for this assignment, and future assignments, will roughly follow this breakdown:

Please let the TA or me know if you have any questions.