Wednesday, February 28, 2007

Lesson 6: State machines

At this point we've covered the basics of the UJML language. You know how to display images, capture user events, set up and execute states, and write functions. Putting this all together, we can create <state-machines>.

A state machine is a collection of state variables, variables, functions, and states that can be used to modularize UJML code. Every state machine has a name which is used as a prefix to the functions and variables of the state machine.

You can create a state machine inline in your UJML code or you can separate it out into another file and include the file in your UJML code. Either way, the state machine code is copied into the UJML code at compile time.

Here is an example of a separately written state machine module. The filename extension is .ujms which indicates that it is a UJML state machine definition.

hello.ujms

<ujml>
   <partition>
      <state-machines>
         <state-machine name="HelloWorld">
            <state-variables>
               <state-var name="sShow" type="boolean"/>
            </state-variables>
            <variables>
               <var name="mName" type="string"/>
            </variables>
            <functions>
               <function name="setName" type="void" visibility="public">
                  <parameters>
                     <var name="aName" type="string"/>
                  </parameters>
                  <script>
                     mName = aName;
                  </script>
               </function>
               <function name="show" type="void" visibility="public">
                  <script>
                     _clear_state(sShow);
                     sShow = true;
                  </script>
               </function>
            </functions>
            <states>
               <state var="sShow">
                  <transition value="true">
                     <display>
                        <label>
                           <text><eval>_strcat("Hello, ", mName, "!")</eval></text>
                        </label>
                     </display>
                  </transition>
               </state>
            </states>
         </state-machine>
      </state-machines>
   </partition>
</ujml>

To use this state machine, you first need to include it into your application.

<ujml>
<application>
    <state-machines>
       <include file="hello.ujms" state-machine="HelloWorld" />
    </state-machines>
    ...
</application>
</ujml>


Now, you can call the state machine functions from any script block.

<ujml>
<application>
    ...
    <script>
       HelloWorld.setName("Lauren");
       HelloWorld.show();
    </script>
    ...
</application>
</ujml>


By separating out this code, you make your main application code simpler and easier to follow. Since the state machine code is encapsulated in another file, you can keep logically separate code isolated.

It is important to be aware of Z-order when using state machines. An application may include the <state-machine> block at either the top of the partition or at the bottom or both. If the state machine is included at the top of the partition, then it will display with a lower Z-order (underneath) the display of the partition. Alternatively, if the state machine is included at the bottom of the partition, it will display with a higher Z-order than the partition's display. This is a common error to make. The clues are that your state machine variables are correct in the debugger but nothing is displayed on the screen. It is likely that your state machine has a lower Z-order than it needs to display correctly.

Another important point is that state machines are not objects. There is no concept of a state machine 'object', so you can't create multiple instances of a state machine. State machines are merely collections of functions, variables, and states that encapsulate some functionality for your application.