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

See here for instructions on how to submit your homework. These instructions will be the same for each assignment.