HCI-631 Project 3: Finite State Machine Interactor
Due: Thursday, 19 October at 11:59pm

In this assignment you will build a new subArctic interactor class.This class will be a "generic interactor" that can perform a variety of different actions based on a finite state machine controller.Specifically your class will do the following:

• accept a data structure which describes a finite state machine (FSM),

• provide a FSM implementation that can interpret any FSM description provided,

• receive inputs from subArctic and translate them into a new set of events,

• use those new events to drive the FSM described by the data structures, and

• carry out the action called for by the FSM controller.

The specific appearance and behavior of this interactor will be customizable by the user of the class (or more to the point, by the test driver for the assignment) by means of a set of data structures described below.These data structures will provide two things: the description of a finite state machine to serve as a controller for the object, and a series of "regions" that will produce output and/or accept input.You will translate inputs received from subArctic into new high level events that are expressed with respect to these regions.You will then use these high level events to drive your finite state controller, which in turn will indicate when you should carry out various actions (such as changing the appearance of a region).

Regions

Each interactor should expect to receive a description of a set of regions.Each region will be described by a region object.This data structure provides a rectangle expressed in the local coordinate system of the interactor (that is with 0,0 referring to the top-left corner of your interactor) and an image.The rectangle indicates the area over which the region will accept input.The image indicates how the region is to appear.All images should be drawn from the top-left of the rectangle for the region.If the image is missing (that is provided as a null pointer value), no image is drawn.Note that the image of the region may extend beyond the input rectangle of the region.

Drawing Your Interactor

The appearance of your interactor is controlled by the set of regions it has been given.Each region has a position and an image.You should draw your interactor (in the draw_self_local() method) by drawing each region image at the top-left of the region in the order in which the regions are given to you in the region array.

The (intrinsic) size of your interactor should be set in the constructor to exactly contain all of its regions.Size should be set using the set_intrinsic_size() method.

Input Handling

Your interactor should be listening for "strokes" -- that is press-drag-release sequences.It will do this by implementing the simple_press_draggable input protocol (i.e., your class will be declared with:

“implements sub_arctic.input.simple_press_draggable”).

The methods implementing this input protocol are: drag_start(), drag_feedback(), and drag_end() (which are documented in simple_press_draggable.java and simple_draggable.java in the sub_arctic.input package).Once you have declared your class to implement simple_press_draggable, it will receive these method calls in response to strokes starting within your interactor.You should implement each of these methods.Together they should act by translating strokes into higher level events that are expressed with respect to regions.In particular, you should translate into the following events:


 
press <region #>
a mouse button has been pressed down within the given region.
release <region #>
a mouse button has been released within the given region.
press none 
a mouse button has been pressed outside any region.
release none
a mouse button has been released outside any region. 
enter <region #>
the mouse has come into the region while a button is held down (or has just been pressed).
exit <region #>
the mouse has left a region while a button is held down (or has just been released).
start
the interactor has just been created

Note that the input that creates a press event also implies an enter event (since the mouse has logically entered the region).Similarly, the input that translates to a release event should also produce an exit event (since the mouse has logically exited the region). Events should be "delivered to" each region that they relate to (in the reverse order that regions are drawn) in turn, until a transition is triggered in the state machine.For example, if the mouse button goes down while the cursor is over regions 7, 9, and 12 (drawn in that order), then the system would attempt to take a transition on press 12.If no transition occurred, then a transition under press 9 would be attempted.If no transition occurred, then a transition under press 7.After the press event(s) had been “sent”, the system would begin trying enter 12, enter 9, and enter 7 (stopping if one of these caused a transition).

Note that when several high level events are produced for a given user input, the order of these events will change the action of the FSM, hence is important, and must match the specification below exactly.

When the user begins a stroke, the press event for each region that the stroke begins over should be delivered (in reverse region drawing order) until one of those events causes a transition.This should then be followed by the enter events for each region (e.g., trying press 5, then press 3, and then trying enter 5, then enter 3).In cases where the stroke begins over no regions, a press_none event should be generated.

When the user moves the mouse with the button still held down, an exit event should be delivered for each region that the cursor had previously been over but is no longer (again in reverse region drawing order) until one of those events causes a transition.This should then be followed by an enter event for each region that the cursor is now over, but was not previously (e.g., trying exit 5, then exit 3, then trying enter 4, and enter 1).

Finally, an exit event for each region the cursor was over at the point of release should be generated.Finally, a release event for each region the mouse was over at the end of the stroke should be generated.In cases where the stroke ends over no regions a release_none event should be generated.

State Machine Control

In addition to a set of regions, each interactor is provided with a data structure that describes the states and transitions of a finite state machine controller.This information is encoded in an array of state objects.The first state in this array will be the start state.The interactor should maintain a current state for this machine and use the events described above to make transitions under control of this machine.Each state of the machine contains a variable number of outgoing transitions which are represented by an array of fsm_transition objects (or null to represent no transitions).Each of these transitions is labeled with an event description that describes the events it may be "taken" under.You should consider these transitions in order and take the first transition that matches the current event.If no transition from the current state matches the current event, the event should be ignored (allowing the system to move to the next candidate event).

Each transition can be labeled with a series of actions to be carried out when that transition is taken.These actions are described by an array of transition_action objects stored with the transition.Actions can be one of the following:
 

set_image(region#, image_filename)set the image of the given region.

callback(n, string)call the interactor callback.

Images should be obtained by passing the string given in the set_image action to the fsm_interactor_base.load_an_image() method that has been provided for you.Note: that the system maintains a cache so it only attempts to load a given image once.

For the callback action recall that subArctic callbacks take 4 parameters: the interactor making the callback (normally you would code this simply as "this"), the event "causing" the callback, the callback number, and a callback specific data object.The event should be taken from the subArctic input routines (or passed as null for transitions under the start event).The callback number should be taken from the callback action, and the string found in the action should be passed as the final parameter.

Object Framework and What You Build

For this assignment you will create a single new interactor class.The interactor class you create must be a sub-class of the fsm_interactor_base class called fsm_interactor. Note that a number of methods in fsm_interactor_base have been declared as abstract.This should serve as a hint as to which subArctic methods need to be overridden to carry out this assignment.

You may not change the fsm_interactor_base class.

The constructor for fsm_interactor must have the form:
 

public fsm_interactor (
intxv,

intyv,

region[]regs,

state[]mach,

callback_object callb)

The flow of control for the resulting program will be as follows:The driver will create FSM and region description data structures from a textual specification (see below). These data structures will be passed to the constructor of your class to produce an fsm_interactor object.That object will then be placed in a window by the driver and normal subArctic event processing will begin.subArctic will provide your interactor with inputs by calling the drag_start(),drag_feedback(), and drag_end() methods.You should respond to these inputs by determining what region(s) they occur in and what higher level events they correspond to.Your interactor should maintain a current state according to the FSM description it has been given.Each higher level event should be used to drive transitions in the FSM.Each time a transition is taken the list of actions associated with the transition should be carried out.

Test Data

To make construction of the data structures needed to control your interactor easier, a parser for a small textual specification language has been built into the main driver for this assignment.This driver expects to receive an interactor specification on its standard input.It will parse this specification, and if it finds it error free, will create the data structures corresponding to that specification.These data structures will be used to create one of your interactors and place it in a window.The syntax for this specification language is as shown below (where non-terminals are in <braces>).
 

<spec>::= <region_list> <state_list>

<region_list>::= <region_spec> | <region_list> <region_spec>

<region_spec>::= region ID at INT , INT , INT , INT <draw_spec>;

<draw_spec>::= drawn with STRING | <empty>

<state_list>::= <empty> | <state_list> <state_spec>

<state_spec>::= state ID <trans_list> end state ;

<trans_list>::= <trans_spec> | <trans_list> <trans_spec>

<trans_spec>::= on <event_spec_list> goto ID <actions> ;

<event_spec_list>::= <event_spec> | <event_spec_list> or <event_spec>

<event_spec>::= start | press ID | release ID | press none | 

release none | enter ID | exit ID | any

<actions>::= <empty> | { <action_list> } 

<action_list>::= <empty> | <action_list> <action_spec>

<action_spec>::= set_image (ID , STRING) ; |

clear_image(ID);

callback ( INT , STRING) ;

Integers, strings, and identifiers are accepted in the same form as Java.

An executable benchmark implementation of the project will be provided.This implementation is instrumented with extra output which indicates which high level events are delivered, which transitions are taken, and which actions are performed (your final program should not have this output).You should refer to this implementation as the standard for questions such as the order of event delivery, etc.

Hints

Based on past experience, a good implementation strategy for this assignment (and many other kinds of programs) is an incremental one.In particular, it is recommended that you implement the following parts of the system one at a time (completely testing the function of that part of the system before moving to the next):

Output of the interactor (based on its regions)

Accepting subArctic drag input

Picking regions based on an input position

Generating candidate high level events based on subArctic drag input

Implementing the FSM transitions based on the high level events

Handling actions specified by the FSM

Finally, if you find that the image of your interactor is not being updated when you change one or more of the images of a region, check to see that you have called damage_self() each time an image is changed.This informs subArctic that your interactor needs to be redrawn.(Note that all drawing must be done in the draw_self_local() method (not the input methods).The (only) correct way to change the appearance is to modify one of the images for a region, then call damage_self() to indicate that a redraw is needed.This will result in your draw_self_local() method being called.)

Turning Your Program In

The program is due Thursday, 19 October at midnight.A penalty will be applied for late assignments.As with the previous projects, you should turn in your assignment by email.For this assignment be sure that the subject of your email contains the string “631 project 3 turnin for “ and your name.Your message should include a single "zip" file (as an attachment) which contains the source code (.java file) for each of your classes.

Grading

Your program will be compiled and run on my machine against test cases unknown to you.The only “extras” for this assignment will be for the sharing of test data.If your package performs properly, is well structured, and is copiously documented you will receive 97 out of 100 points (a high A). Three additional points will be available to anyone who posts a test specification for use by the whole class prior to Friday October 13th at 11:59pm.Test specifications need to come with a good description of what they are supposed to look like and do when run.