Inside UJML

 

 

 

Version 2.1 - December 2006

 

 

 

 

 

 

 

 

 

 

 

www.uievolution.com

Copyright © 2000-2007 UIEvolution, Inc. All rights reserved. UIEVOLUTION, the UIEvolution logo, UIE, and UIENGINE are registered and unregistered trademarks of UIEvolution, Inc. in the United States and/or other countries. Other trademarks are the property of their respective owners.

This document may not be copied or reproduced in any form without the express written permission of UIEvolution, Inc. Information in this document is subject to change without notice.



Audience. 4

Value of UJML. 4

Rich User Experience for Small Devices. 4

Easy to Learn. 4

Example: “Hello World!”. 4

Easy to Deploy to Many Platforms. 6

Supports Client/Server Applications. 7

Secure. 7

Supports a “No Installation” Model 7

UJML Architecture. 7

Static vs. Dynamic. 8

Partitions. 9

Application Development 11

SDK.. 12

Application. 13

Display. 14

States. 16

Z-order 18

Application Logic. 20

Variables. 20

Script 22

Expressions. 25

Functions. 25

Control Flow.. 28

Events. 29

States. 30

Templates. 32

Ujinn. 36

Grid Initialization. 36

Periodic Screen Updates in a Loop. 39

Cursor 41

Removing Boxes. 44

Score Display. 53

Endgame Checking. 56

Menus. 58

Busy Cursor 70

Resuming a Game. 77

Localization. 83

Animation. 90

Reusable Components. 99

<state-machine>. 100

<include>. 103

Examples of State Machines. 104

Busy. 104

Button. 105

Edit 106

Event 107

Focus. 107

FunctionKey. 108

Image. 108

Label 110

Linker 110

Menu. 111

RecordSet 112

ScrollBar 113

Stack. 114

TextBox. 114

List 115

Message Box. 115

 


 

Document History

 

Audience

This guide is for anyone interested in learning how to use Ujinn Markup Language (UJML) to easily develop applications and then deploy them to major phones, PDAs, computer platforms, and embedded devices.

 

Most of this guide is a tutorial which explains how to write a simple game application. Each step in the tutorial introduces one or more UJML concepts in the context of developing the game. Additionally, the guide provides general tips regarding the concepts discussed.

Value of UJML

UJML enables developers to deploy applications that support a rich user experience to a broader audience than any other technology.

Rich User Experience for Small Devices

The designers of UJML used a minimalist approach keep the rendering engine, known as the UIE Player, as small as 30 KB on some Java-enabled devices, and to ensure that the language is simple to learn and use. Yet, UJML can be used to develop applications that provide a rich user experience.

 

UJML is simple, yet powerful.

Easy to Learn

UJML is an XML-based programming markup language that supports a subset of ECMA Script (also called JavaScript).

Example: “Hello World!”

Below are examples of applications that display the text “Hello World” on the device screen. The examples are written in UJML, Java (J2ME/MIDP), and C++ (BREW). Symbian, Palm OS, and Pocket PC versions are not shown because they are similar in complexity to the BREW example. HTML and WML samples are also not shown because they are similar to UJML in terms of their simplicity.

 

This comparison illustrates the simplicity of UJML compared to other programming languages that are available for mobile devices. Not only does a given task require less code, but the language concepts you need to learn, understand, and remember are simpler and shorter.

 

UJML Version:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

      

]>

<ujml>

  <application>

    <display>

      <label>

        <text>Hello world</text>

      </label>

    </display>

  </application>

</ujml>

 

 

J2ME/MIDP Version:

 

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

 

public class HelloWorld extends MIDlet implements CommandListener

{

  private Command exitCommand; // The exit command

  private Display display;   // The display for this MIDlet

 

  public HelloWorld()

  {

       display = Display.getDisplay(this);

       exitCommand = new Command("Exit", Command.SCREEN, 2);

  }

 

  public void startApp()

  {

       TextBox t = new TextBox("", "Hello World", 256, 0);

       t.addCommand(exitCommand);

       t.setCommandListener(this);

       display.setCurrent(t);

  }

 

  public void pauseApp()

  {

  }

 

  public void destroyApp(boolean unconditional)

  {

  }

 

  public void commandAction(Command c, Displayable s)

  {

       if (c == exitCommand)

         {

         destroyApp(false);

         notifyDestroyed();

       }

  }

}

 

BREW Version:

 

#include "AEEModGen.h"      // Module interface definitions

#include "AEEAppGen.h"      // Applet interface definitions

#include "AEEShell.h"       // Shell interface definitions

#include "AEEDisp.h"        // Display interface defintions

#include "helloworld.bid"   // applet class ID

#include "AEEFile.h"        // AEEFile Services

 

static boolean HelloWorld_HandleEvent(IApplet * pi, AEEEvent eCode,  uint16 wParam, uint32 dwParam);

 

int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,void ** ppObj)

{

   *ppObj = NULL;

                            

   if(ClsId == AEECLSID_HELLOWORLD)

   {

      if(AEEApplet_New(sizeof(AEEApplet), ClsId, pIShell,po,(IApplet**)ppObj,

         (AEEHANDLER)HelloWorld_HandleEvent,NULL)  == TRUE)

      {

         return (AEE_SUCCESS);

      }

   }

 

   return (EFAILED);

}

 

static boolean HelloWorld_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam)

   AEEDeviceInfo di;

   AECHAR szBuf[] = {'H','e','l','l','o',' ','W','o', 'r', 'l', 'd', '\0'};

   AEEApplet * pMe = (AEEApplet*)pi;

 

   switch (eCode)

   {

      case EVT_APP_START:                       

         ISHELL_GetDeviceInfo (pMe->m_pIShell, &di);

         IDISPLAY_ClearScreen (pMe->m_pIDisplay);

         IDISPLAY_DrawText(pMe->m_pIDisplay, AEE_FONT_BOLD, szBuf, -1, 0, 0, 0, IDF_ALIGN_CENTER | IDF_ALIGN_MIDDLE);

         IDISPLAY_Update (pMe->m_pIDisplay);

         return(TRUE);

 

      case EVT_APP_STOP:

         return TRUE;

 

      default:

         break;

   }

 

   return FALSE;

}

Easy to Deploy to Many Platforms

The UIE Player is available for the following platforms:

 

Supports Client/Server Applications

In a UJML application, all aspects of application and resource loading use URLs, so the programming model of UJML is designed to make it easy to create dynamic client/server networked applications as well as standalone preinstalled applications. The UIE Player supports both http and file URL schemes, as well as relative URLs.

Secure

UJML applications are interpreted by the UIE Player, which protects the device from faulty or malicious applications; an application that “crashes” is simply unloaded by the UIE Player. This “sandbox” protects UJML applications from each other and also limits the damage a malicious application can inflict on a device.

 

By default, UJML applications are not able to access a device’s features like the file system, phone book, and phone dialer. For custom UIE Players that allow access to device features and resources, the UIE Player configuration allows for flexible security policies that can limit access to resources to trusted UJML applications or partitions. The UIE Player uses a simple URL-based security policy similar to cookie security in HTML/HTTP browsers.

Supports a “No Installation” Model

The UIE Player can use a device’s local storage as a cache of applications so that the user never has to manage application installation on his or her device. The UIE Player simply fetches applications that are not in the cache from the network. When the player needs more space in the cache it discards the least recently used application.

 

This model reduces device operational cost because applications are maintained and deployed using a server, rather than requiring explicit application management on the device. Application updates can be deployed transparently to users because the update is deployed to the server—devices simply load the updated version the next time the user runs the application.

UJML Architecture

UJML is an XML-based markup language that adheres to the UJML DTD. The language describes screen contents in terms of visual states. States also contain blocks of executable code which control how the player transitions between states.

 

UJML is rendered on the device using a small application called the UIE Player, the practical equivalent of an HTML browser. The term ‘player’ is used instead of ‘browser’ because UJML applications are active and dynamic, whereas HTML consists mostly of static pages that are browsed. UJML is more closely akin to Dynamic HTML (DHTML) which supports scripting to add active and dynamic components to static HTML.

 

Unlike most other markup language browsers, the UIE Player does not directly render UJML text files. In order to maximize performance and minimize resource usage (CPU and memory), a UJML text file must be compiled into a byte code file which the UIE Player can render. The compiler compiles UJML into an efficient executable format, thus compressing the raw UJML text file to a much smaller size, efficient for transmitting over costly and low bandwidth wireless networks.

 

Static vs. Dynamic

The compiler can generate precompiled UJML files (called UJBC files) offline, or it can be invoked on-the-fly on a server. The next two diagrams show the components involved in developing and deploying UJML applications via these two methods; the first is precompiled and preloaded on the device, and the second is dynamically compiled on a server in response to a request from the device. Of course, there are many possible variations on these two methods.

 

Diagram: Precompiled Deployment

 

Diagram: Dynamic Compilation Deployment

 

In order to support both of these deployment models, the UIE Player supports the http and file URL schemes.

 

Like HTML browsers, the UIE Player supports the notion of history, so that UJML applications can support the notion of “going back” to the previous application. Applications are added to the history stack in the order they are started using the _run function. A running application removes itself from the stack, causing the previously loaded application to be restarted using the _unload function.

Partitions

A UJML application may consist of multiple partitions, in much the same way as a Web site may consist of multiple HTML pages. The main, or parent, partition of an application is the one that is loaded using the _run function. Child partitions are loaded and unloaded using the _link and _unlink functions. This function-naming convention is borrowed from the world of binary executable applications and DLLs. Depending on their usage, UJML partitions can have the functional characteristics of both HTML pages and binary DLLs. Partitions that have been loaded using the _link function are not added to the history stack. Instead, they are children of their parent partition and are unloaded when the parent is unloaded.

 

Only the current application on the top of the history stack and its linked partitions consume memory resources. Once an application is not on top of the history stack, all memory resources for that application are freed and made available to the new current application.

 

Tip: While an application is being loaded to the top of the history stack, as the result of the _run function being called, the current application consumes memory resources until the new application is finished loading. So, it is important to ensure that neither the previous application nor the new application consume so much memory that both will not fit in memory at the same time.

 

One way to avoid this situation is to use an intermediate “loader application” that uses very little memory.

 

The following diagram gives an example of the UIE Player’s history stack:

The stack might look like this after the following series of events:

 

  1. The player was started with the default application, “App 1.” This placed “App 1” at the bottom, location 0, of the history stack.
  2. “App 1” ran “App 2,” which added “App 2” to the top of the history stack, location 1.
  3. “App 2” linked partition “Part A”.
  4. “App 1” is shown in gray because it is not physically loaded in memory at this point.

 

After “App 2” calls the _unload function to unload itself, the player reloads “App 1” and the history stack and memory usage look like the diagram below:

 

On most devices, the UIE Player is able to cache UJML files locally to avoid refetching them using the network.

 

Also, on many platforms, the UIE Player supports local persistent storage in the form of property bags. This allows applications to store small amounts of data on the device in order to preserve some aspects of their state.

Application Development

In the following sections, we’ll explore many of the features of UJML as we develop the game Ujinn[1]. The game is based on Samegame and has the following basic specification:

 

Application: ujinn

 

Goal:

 

Maximize score while removing as many of the boxes from the grid as possible.

 

Game moves:

 

The player can select a box to remove if that box has at least one adjacent box of

the same color. The adjacent box must be directly above, below, left or right of

the selected box.

 

Scoring:

 

Each time a group is cleared we add (n) * (n - 1) where 'n' is the number of

boxes in the cleared group.

 

At the end of the game the penalty for remaining boxes is the number of remaining

boxes, or the player is given a bonus of (mScore / 4) if they cleared all the boxes.

 

The following screen shots illustrate the game layout and operation.

 

 

After the player selects the current box (upper left), the yellow box and the two “connected” yellow boxes to the right of the current box are cleared.

 

 

SDK

Each section below uses many UJML examples, all of which lead to the development of the game Ujinn. The UJML examples are contained in separate files that accompany this document. The reader is encouraged to install the UIE SDK (from www.uievolution.com) and run the examples in the SDK.

Application

A minimal UJML application is defined as:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

      

]>

 

<ujml>

  <application>

   

  </application>

</ujml>

File: Application.ujml

 

To run this application, follow these steps:

 

  1. Start UIE Developer.
    1. If this is the first time you have run the IDE, choose “New UJML Project” from the Welcome screen. A new project is created for you, and the code for a “Hello World” application is displayed in the editor.
    2. If you have run UIE Developer before, choose File > New > UJML Project. In the “UJML Project” dialog box, name your project “Inside UJML.” Click the “Create a new project in workspace” radio button, and click Finish.
  2. In the Project Explorer view, right-click main.ujml and choose Delete.
  3. Now choose File > New > UJML File. In the “New UJML File” dialog box, click “Inside UJML” to select the parent folder. Where you are prompted to give a “UJML Filename,” specify application.ujml.
  4. If the editor has supplied some default code for you, remove it. Copy the code from the example of application.ujml above and paste it into the editor. Save the changes.
  5. Right-click application.ujml in the Project Explorer view and choose “Set as Main” to set this file as the main source file in the project.
  6. Select the Motorola Razr v3 MIDP skin to use as a device emulator.



  7. Click the Run button on the toolbar.



The perspective changes inside UIE Developer to UJML Debug. After a short delay, the device emulator is displayed:


 

 

Display

Ujinn is a grid-based game, so we need to display some boxes in a grid. We also want to display some game statistics at the top of the screen, like the current score, the level, and so on.

 

The simplest way to display something on the screen is to put it in a <display> element.   The example below draws the text “Score” and a box:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

      

]>

<ujml>

    <application>

        <display>

            <label>

                <text>Score</text>

                <x>2</x>

                <y>2</y>

                <fg>&_COLOR_BLUE;</fg>

            </label>

            <box>

                <x>5</x>

                <y>20</y>

                <width>30</width>

                <height>50</height>

                <fg>&_COLOR_RED;</fg>

                <bg>&_COLOR_GREEN;</bg>

            </box>

        </display>

    </application>

</ujml>

File: Display.ujml

 

When you run display.ujml in UIE Developer, you will see this:

 

 

This example uses the default <display> element. The default setting is intended for static backgrounds because there is no way to update the contents of the default display.

States

For dynamic display elements, UJML allows the programmer to define additional <display> elements that can be controlled (displayed, updated, or hidden) programmatically by changing the values of state variables. These changes are called state transitions.

 

A UJML state associates one or more <display> elements to the values that a variable can contain. For example, since a Boolean variable can have two values, it can be in one of two states, true or false. In UJML it is possible to define <display> elements for each of these values, or states.

 

In the example below, the Boolean state variable sBox has a single <display> element defined for the state value true. When sBox is set to true, the box is displayed on the screen. When it is set to false the box is hidden, because there is no <display> element defined for the value false.

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sBox" type="boolean"/>

        </state-variables>

        <script>

            sBox = true;

        </script>

        <states>

            <state var="sBox">

                <transition value="true">

                    <display>

                        <box>

                            <x>5</x>

                            <y>20</y>

                            <width>30</width>

                            <height>50</height>

                            <fg>&_COLOR_RED;</fg>

                            <bg>&_COLOR_GREEN;</bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: DisplayState.ujml

 

When you run displaystate.ujml in UIE Developer, you will see this:

 

 

The example below changes the previous displaystate.ujml application to use separate <display> elements for the text and the box. This allows the application to control them independently by setting the corresponding state variables to either true or false to show or hide the items:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean"/>

        </state-variables>

        <script>

            sScore = true;

            sBox = true;

        </script>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text>Score</text>

                            <x>2</x>

                            <y>2</y>

                            <fg>&_COLOR_BLUE;</fg>

                        </label>

                    </display>

                </transition>

            </state>

            <state var="sBox">

                <transition value="true">

                    <display>

                        <box>

                            <x>5</x>

                            <y>20</y>

                            <width>30</width>

                            <height>50</height>

                            <fg>&_COLOR_RED;</fg>

                            <bg>&_COLOR_GREEN;</bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: DisplayStates.ujml

 

The single most important thing to remember about UJML and states is this:

 

The only way to change the display is by changing the values of state variables that have <display> elements associated with them.

 

Setting a state variable to a value that it already contains will not affect the display. The value must change to change the display[2]. This means that integer state variables are more powerful than Boolean variables; if you need to do anything more with a state variable than display and hide an item on the screen, you will need to use an integer. (A Boolean state variable would use true to show the <display> and false to hide it, and that would be the extent of its abilities.)

Z-order

The <display> elements are drawn on the display with a back-to-front z-order, which matches the order in which the <display> elements appear in the UJML source file. The default <display> is in the background, lowest in the z-order, and the last <display> in the file is in the foreground, highest in the z-order[3].

 

The following example adds two more boxes and a background to displaystates.ujml. It also shows how to create and use arrays in UJML; we have changed sBox from a simple Boolean variable to a Boolean array with three elements, one for each box we want to display. Finally, the program shows how ARGB (alpha, red, green, blue) values can be specified for the colors of visual elements.

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean" size="3"/>

        </state-variables>

        <script>

            sScore = true;

            sBox[ 0 ] = true;

            sBox[ 1 ] = true;

            sBox[ 2 ] = true;

        </script>

        <display>

            <box>

                <width>136</width>

                <height>140</height>

            </box>

        </display>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text>Score</text>

                            <x>2</x>

                            <y>2</y>

                            <fg>&_COLOR_BLUE;</fg>

                        </label>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="0">

                <transition value="true">

                    <display>

                        <box>

                            <x>5</x>

                            <y>20</y>

                            <width>30</width>

                            <height>50</height>

                            <fg>0xffcccccc</fg>

                            <bg>0xffcccccc</bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="1">

                <transition value="true">

                    <display>

                        <box>

                            <x>10</x>

                            <y>25</y>

                            <width>30</width>

                            <height>50</height>

                            <fg>0xff999999</fg>

                            <bg>0xff999999</bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="2">

                <transition value="true">

                    <display>

                        <box>

                            <x>15</x>

                            <y>30</y>

                            <width>30</width>

                            <height>50</height>

                            <fg>0xff666666</fg>

                            <bg>0xff666666</bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: DisplayZOrder.ujml

 

When you run displayzorder.ujml in UIE Developer, you will see this:

 

Application Logic

So far we’ve discussed how to display things on the screen and hinted at how programming logic is expressed in UJML using the <script> element. UJML supports variables, arithmetic expressions, logical/Boolean expressions, string expressions, control flow statements, functions, and events.

Variables

We’ve already seen how to declare and use state variables. Since there is a certain amount of internal overhead for state variables to support state transitions, UJML also supports simple variables which have no states associated with them. Both state variables and simple variables can be used in expressions and executable statements in the same way as variables are used in any other programming language.

 

The example below adds variables for the score value and box colors. It shows how to use XML entity definitions for declaring constant values and how to use variables and constants in display elements.

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_BOXES "3">

    <!ENTITY BOX_WIDTH "30">

    <!ENTITY BOX_HEIGHT "50">

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean" size="&MAX_BOXES;"/>

        </state-variables>

        <variables>

            <var name="mScore" type="int"/>

            <var name="mBox" type="int" size="&MAX_BOXES;"/>

        </variables>

        <script>

            mScore = 0;

            sScore = true;

            mBox[ 0 ] = 0xffcccccc;

            sBox[ 0 ] = true;

            mBox[ 1 ] = 0xff999999;

            sBox[ 1 ] = true;

            mBox[ 2 ] = 0xff666666;

            sBox[ 2 ] = true;

        </script>

        <display>

            <box>

                <width>136</width> <height>140</height>

            </box>

        </display>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text><eval>mScore</eval></text>

                            <x>2</x> <y>2</y>

                            <fg>&_COLOR_BLUE;</fg>

                        </label>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="0">

                <transition value="true">

                    <display>

                        <box>

                            <x>5</x> <y>20</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg><eval>mBox[ 0 ]</eval></fg>

                            <bg><eval>mBox[ 0 ]</eval></bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="1">

                <transition value="true">

                    <display>

                        <box>

                            <x>10</x> <y>25</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg><eval>mBox[ 1 ]</eval></fg>

                            <bg><eval>mBox[ 1 ]</eval></bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="2">

                <transition value="true">

                    <display>

                        <box>

                            <x>15</x> <y>30</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg><eval>mBox[ 2 ]</eval></fg>

                            <bg><eval>mBox[ 2 ]</eval></bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: Variables.ujml

 

When you run variables.ujml in UIE Developer, you will see this:

 

 

Script

UJML supports two scripting languages for evaluating expressions and controlling application flow. The previous examples have used UJML’s subset of ECMAScript (JavaScript). JavaScript is contained in the <script> element. If you are familiar with programming languages like C, C++, Java, or JavaScript, you will probably prefer to use JavaScript in UJML applications.

 

UJML also supports UJMLscript, which has the same capabilities as JavaScript but retains the XML syntax. UJMLscript is contained in the <execute> element. If you are unfamiliar with the languages listed above, you may find UJMLscript easier to learn initially, but may find JavaScript easier later when the programming logic of the applications becomes more complex. This is because UJMLscript is verbose and difficult to read when doing complex calculations or program-control flow.

 

Except for the following example, that shows equivalent JavaScript and UJMLscript, this document uses JavaScript in all examples.

 

The following example is the UJMLscript equivalent of the previous variables.ujml example:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_BOXES "3">

    <!ENTITY BOX_WIDTH "30">

    <!ENTITY BOX_HEIGHT "50">

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean" size="&MAX_BOXES;"/>

        </state-variables>

        <variables>

            <var name="mScore" type="int"/>

            <var name="mBox" type="int" size="&MAX_BOXES;"/>

        </variables>

        <execute>

            <set var="mScore">0</set>

            <set-state var="sScore">true</set-state>

            <set var="mBox">

                <index>0</index>

                <val>0xffcccccc</val>

            </set>

            <set-state var="sBox">

                <index>0</index>

                <val>true</val>

            </set-state>

            <set var="mBox">

                <index>1</index>

                <val>0xff999999</val>

            </set>

            <set-state var="sBox">

                <index>1</index>

                <val>true</val>

            </set-state>

            <set var="mBox">

                <index>2</index>

                <val>0xff666666</val>

            </set>

            <set-state var="sBox">

                <index>2</index>

                <val>true</val>

            </set-state>

        </execute>

        <display>

            <box>

                <width>136</width>

                <height>140</height>

            </box>

        </display>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text>

                                <ref var="mScore"/>

                            </text>

                            <x>2</x>

                            <y>2</y>

                            <fg>&_COLOR_BLUE;</fg>

                        </label>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="0">

                <transition value="true">

                    <display>

                        <box>

                            <x>5</x>

                            <y>20</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg>

                                <ref var="mBox">

                                    <index>0</index>

                                </ref>

                            </fg>

                            <bg>

                                <ref var="mBox">

                                    <index>0</index>

                                </ref>

                            </bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="1">

                <transition value="true">

                    <display>

                        <box>

                            <x>10</x>

                            <y>25</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg>

                                <ref var="mBox">

                                    <index>1</index>

                                </ref>

                            </fg>

                            <bg>

                                <ref var="mBox">

                                    <index>1</index>

                                </ref>

                            </bg>

                        </box>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="2">

                <transition value="true">

                    <display>

                        <box>

                            <x>15</x>

                            <y>30</y>

                            <width>&BOX_WIDTH;</width>

                            <height>&BOX_HEIGHT;</height>

                            <fg>

                                <ref var="mBox">

                                    <index>2</index>

                                </ref>

                            </fg>

                            <bg>

                                <ref var="mBox">

                                    <index>2</index>

                                </ref>

                            </bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: UJMLscript.ujml

Expressions

UJML supports most common mathematical, logical, and string operators. An expression can appear in script or serve as UJML element content (for elements that allow values or variable references). In this latter case, the expression must either be UJMLscript or a JavaScript expression within an <eval> element. However, expressions may not appear in UJML element attribute values because, in UJML, all attribute values are static constants.

 

Here are examples of valid and invalid uses of expressions:

 

Valid

Invalid

<script>

  x = y * 3;

</script>

 

<box>

  <width><eval>w / 3</eval></width>

  <height><eval>h / 3</eval></height>

</box>

<state var=”x + y” index=”z / 8”>

 

 

 

Functions

Many utility functions are built into UJML. Applications can also define their own functions.

 

The example below uses expressions and several built-in functions to dynamically lay out the screen so that it will scale to the current device’s screen size. The example also shows how to use a default state to define an identical state for all the elements of an array state variable.

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_BOXES "3">

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean" size="&MAX_BOXES;"/>

        </state-variables>

        <variables>

            <var name="mScore" type="int"/>

            <var name="mBox" type="int" size="&MAX_BOXES;"/>

            <var name="mTextHeight" type="int"/>

            <var name="mScrWidth" type="int"/>

            <var name="mScrHeight" type="int"/>

            <var name="mBoxWidth" type="int"/>

            <var name="mBoxHeight" type="int"/>

        </variables>

        <script>

            mTextHeight = _text_height( 0, 0, 0 );

            mScrWidth = _getIntProperty( &_PROPERTY_INT_SCREEN_WIDTH; );

            mScrHeight = _getIntProperty( &_PROPERTY_INT_SCREEN_HEIGHT; );

            mBoxWidth = mScrWidth / &MAX_BOXES;;

            mBoxHeight = mScrHeight - mTextHeight;

            mScore = 0;

            sScore = true;

            mBox[ 0 ] = 0xffcccccc;

            sBox[ 0 ] = true;

            mBox[ 1 ] = 0xff999999;

            sBox[ 1 ] = true;

            mBox[ 2 ] = 0xff666666;

            sBox[ 2 ] = true;

        </script>

        <display>

            <box>

                <width> <eval>mScrWidth</eval> </width>

                <height> <eval>mScrHeight</eval> </height>

                <fg>&_COLOR_BLACK;</fg>

                <bg>&_COLOR_BLACK;</bg>

            </box>

        </display>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text> <eval>mScore</eval> </text>

                            <x>1</x> <y>1</y>

                            <fg>&_COLOR_YELLOW;</fg>

                        </label>

                    </display>

                </transition>

            </state>

 

Below we define a single default state for all the elements in the array state variable sBox. The main purpose of using a default state is to reduce the amount of UJML code that needs to be written when all the states for the array are identical[4].

 

            <state var="sBox" index="*">

                <transition value="true">

                    <display>

                        <box>

                            <x> <eval>_state_index() * mBoxWidth</eval> </x>

                            <y> <eval>mTextHeight</eval> </y>

                            <width> <eval>mBoxWidth</eval> </width>

                            <height> <eval>mBoxHeight</eval> </height>

                            <fg> <eval>mBox[ _state_index() ]</eval> </fg>

                            <bg> <eval>mBox[ _state_index() ]</eval> </bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

File: Functions.ujml

 

The display on several device skins in the emulator looks like this:

 

 

 

It is generally a good idea to write applications that automatically scale to the device screen. It may be difficult or unnecessary to develop an application that looks good on both a vertical screen format and a horizontal screen format, but many groups of phones have screens in the same format but with differing sizes. Making the application look good on the same screen format (vertical phone screens, for example) and within the wide range of screen-size variances is a good goal; designing your application like this will enable you to distribute it to as many devices as possible with few, if any, modifications.

Control Flow

UJML supports the if, while, and for control-flow constructs; switch is not supported.

 

The example below uses a while loop to display all the boxes in an array. A function is used to calculate the x-location of each box:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_BOXES "3">

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <state-var name="sBox" type="boolean" size="&MAX_BOXES;"/>

        </state-variables>

        <variables>

            <var name="mScore" type="int"/>

            <var name="mBox" type="int" size="&MAX_BOXES;"/>

            <var name="mTextHeight" type="int"/>

            <var name="mScrWidth" type="int"/>

            <var name="mScrHeight" type="int"/>

            <var name="mBoxWidth" type="int"/>

            <var name="mBoxHeight" type="int"/>

            <var name="i" type="int"/>

        </variables>

        <functions>

            <function name="getX" type="int">

                <parameters>

                    <var name="box" type="int"/>

                </parameters>

                <variables>

                    <var name="x" type="int"/>

                </variables>

                <script>

                    x = box * mBoxWidth;

                </script>

                <return>

                    <eval>x</eval>

                </return>

            </function>

        </functions>

        <script>

            mTextHeight = _text_height( 0, 0, 0 );

            mScrWidth = _getIntProperty( &_PROPERTY_INT_SCREEN_WIDTH; );

            mScrHeight = _getIntProperty( &_PROPERTY_INT_SCREEN_HEIGHT; );

            mBoxWidth = mScrWidth / &MAX_BOXES;;

            mBoxHeight = mScrHeight - mTextHeight;

            mScore = 0;

            sScore = true;

 

            mBox[ 0 ] = 0xffcccccc;

            mBox[ 1 ] = 0xff999999;

            mBox[ 2 ] = 0xff666666;

 

            while (i &lt; &MAX_BOXES;)

            {

                sBox[ i ] = true;

                i = i + 1;

            }

        </script>

        <display>

            <box>

                <width> <eval>mScrWidth</eval> </width>

                <height> <eval>mScrHeight</eval> </height>

                <fg>&_COLOR_BLACK;</fg>

                <bg>&_COLOR_BLACK;</bg>

            </box>

        </display>

        <states>

            <state var="sScore">

                <transition value="true">

                    <display>

                        <label>

                            <text> <eval>mScore</eval> </text>

                            <x>1</x> <y>1</y>

                            <fg>&_COLOR_YELLOW;</fg>

                        </label>

                    </display>

                </transition>

            </state>

            <state var="sBox" index="*">

                <transition value="true">

                    <display>

                        <box>

                            <x><eval>getX( _state_index() )</eval></x>

                            <y> <eval>mTextHeight</eval> </y>

                            <width> <eval>mBoxWidth</eval> </width>

                            <height> <eval>mBoxHeight</eval> </height>

                            <fg> <eval>mBox[ _state_index() ]</eval> </fg>

                            <bg> <eval>mBox[ _state_index() ]</eval> </bg>

                        </box>

                    </display>

                </transition>

            </state>

        </states>

    </application>

</ujml>

            File: While.ujml

Events

User actions and system-status changes are communicated to a UJML application using events.

 

The following example adds an event handler when the user presses the F1 function key. The event handler unloads the application when F1 is pressed. Rather than repeat all the code from the Ujinn sample, this example shows only the addition of the <fn> element to the <display> element of the sample. (The <fn> element defines a function key.)

 

       <!-- Previous code from Ujinn sample is unchanged. -->

        <display>

            <box>

                <width> <eval>mScrWidth</eval> </width>

                <height> <eval>mScrHeight</eval> </height>

                <fg>&_COLOR_BLACK;</fg>

                <bg>&_COLOR_BLACK;</bg>

            </box>

            <fn>

                <text>Back</text>

                <event name="onselect">

                    <accelerators>

                        <key>F1</key>

                    </accelerators>

                    <script>

                        _unload();

                    </script>

                </event>

            </fn>

        </display>

    </application>

</ujml>

            File: Events.ujml

 

Tip: Always use the F1 key for Back functionality. This behavior is required by some platforms, like BREW, and it fits well with the overall user experience on many devices. Most phones have the notion of Back or Clear buttons and Sony’s CLIE PDAs also have a Back button.

 

Events may be associated with a visual element only in a <display> element.

 

Tip: To create an event handler when you don’t need a visible visual element, use an empty or transparent <box> element.

States

In additions to defining <display> elements, states can define application logic that is executed when the state becomes active. (In this case, the state variable changes to the specified value inside the <transition> element.)

 

The following example displays a message box and uses a delayed script to hide the box after five seconds. Add the following two lines (shown in bold) to the Ujinn sample code:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_BOXES "3">

]>

<ujml>

    <application>

        <state-variables>

          …

            <state-var name="sMessageBox" type="boolean"/>

        </state-variables>

        <variables>

          …

        </variables>

        <script>

          …

            sMessageBox = true;

        </script>

        <display>

          …

        </display>

        <states>

          …

 

When the state variable sMessageBox is set to true, the transition below is executed by the UIE Player.

 

            <state var="sMessageBox">

                <transition value="true">

                    <display>

                        <multi-label>

                            <text>This is a message box.</text>

                            <x>10</x>

                            <y>30</y>

                            <width><eval>mScrWidth - 20</eval></width>

                            <height><eval>mScrHeight - 60</eval></height>

                            <fg>&_COLOR_LIME;</fg>

                            <bg>&_COLOR_MAROON;</bg>

                        </multi-label>

                    </display>

                    <delay>5000</delay>

                    <script>

                        sMessageBox = false;

                    </script>

                </transition>

            </state>

        </states>

    </application>

</ujml>

            File: ScriptStates.ujml

 

First, the <display> element is processed and added to the UIE Player’s internal “display list,” which it uses to paint the screen. Since the sMessageBox variable is true, the message box is displayed. Next, the <script> element is processed; however, since it follows a <delay> element, instead of executing the <script> element, the UIE Player adds the element to a queue so that it will be executed after a five second delay. This means that the message box is visible for five seconds, until sMessageBox is set to false inside the <script> element.

 

When you run scriptstates.ujml in UIE Developer, you will see this:

 

 

Common reasons for using script in a state include:

Templates

Because the Ujinn game uses an 8x8 grid for the game play area, we need to update our sample application to use a two-dimensional state-variable array. We also introduce a color-map array which is used for the game piece colors. (Later, we’ll initialize this color map based on whether or not the device supports color.)

 

Some of the most important changes to our application are pointed out with comments below:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ujml PUBLIC "-//UIEVOLUTION//DTD UJML 2.1//EN" "http://www.uievolution.com/dtd/ujml-2.1.dtd" [

    <!ENTITY MAX_ROWS "8">

    <!ENTITY MAX_COLS "8">

    <!ENTITY MAX_COLORS "4">

]>

<ujml>

    <application>

        <state-variables>

            <state-var name="sScore" type="boolean"/>

            <!--

            The sBoxes state variable replaces the sBox state

            variable from earlier versions of Ujinn.

            -->

            <state-var name="sBoxes" type="boolean" size="&MAX_ROWS;,&MAX_COLS;"/>            

        </state-variables>

        <variables>

            <var name="mScore" type="int"/>

            <var name="mTextHeight" type="int"/>

            <var name="mScrWidth" type="int"/>

            <var name="mScrHeight" type="int"/>

            <var name="mBoxWidth" type="int"/>

            <var name="mBoxHeight" type="int"/>

            <!--

            The mBoxes variable replaces the mBox variable

            -->

            <var name="mBoxes" type="int" size="&MAX_ROWS;,&MAX_COLS;"/>                       

            <!-- The next three variables are new. -->

            <var name="mColorMap" type="int" size="&MAX_COLORS;"/>

            <var name="r" type="int"/>

            <var name="c" type="int"/>

        </variables>

        <script>

            mTextHeight = _text_height( 0, 0, 0 );

            mScrWidth = _getIntProperty( &_PROPERTY_INT_SCREEN_WIDTH; );

            mScrHeight = _getIntProperty( &_PROPERTY_INT_SCREEN_HEIGHT; );

            <!--

            The next two lines change the width and height of the boxes

            proportionally to the device screen.

            -->

            mBoxWidth = mScrWidth / &MAX_COLS;;

            mBoxHeight = mScrHeight / &MAX_ROWS;;

            mScore = 0;

            sScore = true;

            <!-- Initialize the color map array. -->

            mColorMap[ 0 ] = 0xffcccccc;

            mColorMap[ 1 ] = 0xff999999;

            mColorMap[ 2 ] = 0xff666666;

            mColorMap[ 3 ] = 0xff333333;

            <!-- Fill in the box arrays. -->

            while (r &lt; &MAX_ROWS;)

            {

                c = 0;

                while (c &lt; &MAX_COLS;)

                {

                    mBoxes[ r ][ c ] = mColorMap[ (r + c) % &MAX_COLORS; ];

                    sBoxes[ r ][ c ] = true;

                    c = c + 1;

                }

                r = r + 1;

            }

        </script>

        <display>

            <box>

                <width> <eval>mScrWidth</eval> </width>

                <height> <eval>mScrHeight</eval> </height>

                <fg>&_COLOR_BLACK;</fg>

                <bg>&_COLOR_BLACK;</bg>

            </box>