Monday, August 28, 2006

Lesson 4b: State variables and transitions

In the previous sublesson, I mentioned state variables and that they may be used to display visual elements. This is a simplification of their purpose, but in regards to displays, state variables are the only way to update the display.

I find that thinking of applications as a series of screens helps me understand the concept behind state variables. On mobile phones, this is very obvious. You press the menu button to show the menu (a screen), you select an item from the menu and it loads a different part of the application (another screen). Any of the menu items may lead to any number of other screens. One screen, in other words, may have many different screen transitions.

In a typical programming language, you'd set up an object's member variables (color=red, size=10, etc) and then call a method which then performs some processing based upon the updated object state. A state is defined in this situation by its defining characteristics (variables) and its behavior is defined by the results of the execution (method). To change state, the program must explicitly call the state transition with the correct variables. If the input parameters are incorrect, the program may behave in an undefined manner.

UJML introduces the concept of state variables. They are different from normal variables because they have special knowledge about their internal values. When a state variable's value changes, it reacts by executing a script defined for that particular value. This leads to two fundamental properties of state variables:

1) State variables may be any type except for reference data types.
2) State variable execution scripts can be called implicitly by the UIE Player.

The second property is the more interesting of the two. By simply changing the value of a state variable, the specified script is executed.

State variables are declared as follows:

<ujml>
   <application>
      <state-variables>
         <state-var name="sPaintScreen" type="boolean" />
      </state-variables>
   </application>
</ujml>

The state variable is scoped to the entire application block, so it may be accessed anywhere from within the block. It is also possible to define state variables that have more restricted scope, but I'll try to cover that later when I discuss state machines.

When a state variable is updated, it transitions to a new state. This is called a state transition. A state transition may contain a display routine, audio routine, script routine, or a resource definition. It may also use a variable declaration to provide any necessary local variables to the script.

This is an example of a simple state transition that displays an image.

<state var="sPaintScreen">
   <transition value="true">
      <display>
         <image>
            <url>http://photos1.blogger.com/img/158/8299/320/050923_003L1.jpg</url>
            <x>0</x>
            <y>0</x>
            <width>240</width>
            <height>320</height>
         </image>
      </display>
   </transition>
</state>

This state transition will display the specified image on the screen when the 'sPaintScreen' state variable is set to "true". When 'sPaintScreen' is set to "false", anything specified in the "true" transition will be deleted. In short, "true" shows the image, and "false" hides the image.

Now, to paint the image to the screen, the application's script just sets the sPaintScreen state variable to true.

<ujml>
   <application>
      <state-variables>
         <state-var name="sPaintScreen" type="boolean" />
      </state-variables>
      <script>
         // Paint the image
         sPaintScreen = true;
      </script>
      <states>
         <state var="sPaintScreen">
            <transition value="true">
               <display>
                  <image>
                     <url>http://photos1.blogger.com/img/158/8299/320/050923_003L1.jpg</url>
                     <x>0</x>
                     <y>0</y>
                     <width>240</width>
                     <height>320</height>
                  </image>
               </display>
            </transition>
         </state>
      </states>
   </application>
</ujml>

The code above does essentially the same thing as the code in the previous lesson. The difference is that this version separates the painting of the image from the application display. When a visual element is included directly in the application's display, it remains on the screen at the lowest Z-order. By moving the visual element into a state transition display, it can be shown and erased from the display programmatically.

We previously used function key accelerators to handle user interactions. If we use the same technique here, we can update the display in response to user key presses.

<fn>
   <text>Update Display</text>
   <event name="onselect">
      <accelerators>
         <key>F1</key>
      </accelerators>
      <script>
         // flip flop the boolean value
         sPaintScreen = !sPaintScreen;
      </script>
   </event>
</fn>

This key handler will either show or erase the image on the screen when the user presses the F1 key. The program we have been working on is now interactive!

<ujml>
   <application>
      <state-variables>
         <state-var name="sPaintScreen" type="boolean" />
      </state-variables>
      <script>
         // Paint the image
         sPaintScreen = true;
      </script>
      <display>
         <fn>
            <text>Update Display</text>
            <event name="onselect">
               <accelerators>
                  <key>F1</key>
               </accelerators>
               <script>
                  // flip flop the boolean value
                  sPaintScreen = !sPaintScreen;
               </script>
            </event>
         </fn>
      </display>
      <states>
         <state var="sPaintScreen">
            <transition value="true">
               <display>
                  <image>
                     <url>http://photos1.blogger.com/img/158/8299/320/050923_003L1.jpg</url>
                     <x>0</x>
                     <y>0</y>
                     <width>240</width>
                     <height>320</height>
                  </image>
               </display>
            </transition>
         </state>
      </states>
   </application>
</ujml>

Briefly, the above code declares a state variable called 'sPaintScreen'. The sPaintScreen variable is set to 'true' which puts the sPaintScreen=true state transition into the queue. The display is updated with the F1 key bound to the 'onselect' event. The pending state transition is executed and the image is shown on the screen. When the user presses the F1 key, sPaintScreen is set to 'false' which then erases any visual elements specified in 'true'. Since there is no explicit 'false' transition, no special handling is performed. If the user presses the F1 key again, sPaintScreen is set to 'true' which puts the image back on the screen.

Try the code and play with it for a little while. Investigate adding an event handler into the sPaintScreen=true state transition. Doing so will allow you to change the text of the F1 key accelerator.

Next time I will cover using the resources tag to manage the handling of images.

0 Comments:

Post a Comment

<< Home