The State Machine
The state machine has five states controlled by two events, one for left page flips and one for right flips. The machine controls and coordinates the pages of the album and the sound effects of the album. The sample uses notification objects because of the cyclic dependency in the finite state machine (not because of event data, which is the second purpose for using notification objects). Notification objects, by providing a delayed execution construct, make it possible to construct cyclic calling dependencies without infinite looping. The sample also uses the until2 method instead of untilNotify since it allows the aggregatation of two notification events each with a different notification method; see the opened state below.
Note that both cyclic dependency and branching from one state into two or more states upon different events are commonly occuring patterns in general state machines. Hence the example below has the building blocks that are needed for typical state machines.

This state is the entry point into the state machine and is also returned to upon flipping the front page back (effectively going back to the start state). It sets the left page to blank, the right page to the front page of the album, and it emits the page-flip completion sound through the right speaker. The state waits on the leftEventNotify event upon which it invokes the transLeft notification object which implements the "transition left" state.

public static TupleBvr frontState () {
NumberBvr leftInd = toBvr(0);
Behavior newBvrs[] = { leftInd, add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(+1)};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, leftEventNotify);
}

This state is entered upon the end of a page flip that causes the album to be properly opened (i.e., not in a boundary condition). It waits on either a left or a right event, at which point it invokes the transLeft or transRight notification objects, respectively, which carry it through either the left transition or to right transition state. It accepts an index to the left page plus the side to which the previous page was flipped to, in order to emit the page flip termination sound.

public static TupleBvr opened (NumberBvr leftInd, int side) {
Behavior newBvrs[] = {leftInd , add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(toBvr(side))};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, orEvent(rightEventNotify,
leftEventNotify));
}

symmetric to frontState

public static TupleBvr backState () {
NumberBvr leftInd = toBvr(A3DM.numPics);
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(-1)};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, rightEventNotify);
}

This notifier object flips the center page to the left side until the completion of the page flip. At that point if we've flipped the last page then we go to the back state, else we go to the opened state, which is the nominal one. Notice how we extract the present left page index from the "previous" parameter of the "notify" method.

class TransLeft extends Statics implements UntilNotifier {
public Behavior notify(Object eventData, Behavior previous, BvrsToRun blst) {
NumberBvr leftInd = (NumberBvr)((TupleBvr)previous).nth(0);
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(2)),
A3DM.flip(add(leftInd, toBvr(1)), -1), A3DM.flippingSnd(-1)};
return (TupleBvr) until(new TupleBvr(newBvrs), A3DM.endFlip,
cond(eq(leftInd, toBvr(A3DM.numPics - 1)),
A3DM.backState(),
A3DM.opened(add(leftInd, toBvr(1)), -1)));
}
}

symmetric to TransLeft

class TransRight extends Statics implements UntilNotifier {
public Behavior notify(Object eventData, Behavior previous, BvrsToRun blst) {
NumberBvr leftInd = sub((NumberBvr)((TupleBvr)previous).nth(0), toBvr(1));
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(2)),
A3DM.flip(add(leftInd, toBvr(1)), +1), A3DM.flippingSnd(+1)};
return (TupleBvr) until(new TupleBvr(newBvrs), A3DM.endFlip,
cond(eq(leftInd, toBvr(0)),
A3DM.frontState(),
A3DM.opened(leftInd, +1)));
}
}

interaction events Right and left arrows to flip pages.

static final DXMEvent rightEvent = keyDown(Event.RIGHT);
static final DXMEvent leftEvent = keyDown(Event.LEFT);

signals the conclusion of a page flip animation

static final DXMEvent endFlip = timer(toBvr(period));

instantiate the notifier objects

static final TransRight transRight = new TransRight();
static final TransLeft transLeft = new TransLeft();

Define notify events based on the previous objects, these events get used in the state machine.

static final DXMEvent rightEventNotify = rightEvent.notifyEvent(transRight);
static final DXMEvent leftEventNotify = leftEvent.notifyEvent(transLeft);
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.