UIEvolutin Inc.
UJML Language Reference
lifegrid.ujml

The lifegrid.ujml sample is a visual component that displays a grid of blocks (cells) in the Life sample simulation grid.

This sample is a visual component that displays grid of blocks (cells) in the Life sample simulation grid. See Samples, Components, Interfaces. The actual cells are displayed by instances of the lifeblock.ujml component. 

This is the 'heavy' grid component sample, which delegates grid display to a block component, and must manage a list of block component instances. This means that each block in the grid represents a separate component instance, with its own memory and performance overhead. Although this kind of design might be preferable from a code-reuse and conceptual viewpoint, it doesn't represent the most efficient way to code UJML components for devices with limited resources.

<?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 % lifedeclares SYSTEM "life.ent">
    %lifedeclares;
]>
<!--
    Copyright (c) 2000-2007 UIEvolution, Inc. U.S.A.
    http://www.uievolution.com
    All rights reserved.

    Provided under the Software License Agreement for Non-commercial Use of
    UIEvolution Platform Software - modification and incorporation into
    applications allowed, subject to the terms thereof.
-->

<!--
    lifegrid.ujml

    Heavyweight grid component for the Life sample application, which uses
    separate instances of the LifeBlock component for each grid block.
-->
<ujml>
    <interfaces>
        <include interface="ILifeGrid" file="ilife.ujmi"/>
        <include interface="ILifeBlock" file="ilife.ujmi"/>
        <interface name="ITimerListener"/><!-- Forward declaration. -->
        <include interface="ITimerSource" file="../shared/itimer.ujmi"/>
    </interfaces>

    <component name="LifeGrid">
        <interfaces>
            <interface name="ILifeGrid" access="export"/>
        </interfaces>

        <state-variables>
            <state-var name="sGridBackground" type="boolean"/>
            <state-var name="sGridHeader" type="boolean"/>
            <state-var name="sGridBlocks" type="boolean" size="&MAX_ROWS;, &MAX_COLS;"/>
            <state-var name="sRunning" type="boolean"/>
        </state-variables>

        <variables>
            <var name="mTimers" type="ITimerSource"/>
            <var name="mBlocks" type="ILifeBlock" size="0, 0"/>
            <var name="mRows" type="int"/>
            <var name="mCols" type="int"/>
            <var name="mX" type="int"/>
            <var name="mY" type="int"/>
            <var name="mWidth" type="int"/>
            <var name="mHeight" type="int"/>
            <var name="mHeaderHeight" type="int"/>
            <var name="mSelectedRow" type="int"/>
            <var name="mSelectedCol" type="int"/>
            <var name="mGeneration" type="int"/>
        </variables>

        <functions>
            <!--
                Initializes the grid.
            -->
            <function name="ILifeGrid.init" type="void">
                <parameters>
                    <var name="x" type="int"/>
                    <var name="y" type="int"/>
                    <var name="width" type="int"/>
                    <var name="height" type="int"/>
                    <var name="boxHeight" type="int"/>
                    <var name="boxWidth" type="int"/>
                </parameters>
                <variables>
                    <var name="rowCtr" type="int"/>
                    <var name="colCtr" type="int"/>
                    <var name="leftOffset" type="int"/>
                    <var name="topOffset" type="int"/>
                    <var name="xPos" type="int"/>
                    <var name="yPos" type="int"/>
                    <var name="upperLeft" type="ILifeBlock"/>
                    <var name="upperMiddle" type="ILifeBlock"/>
                    <var name="upperRight" type="ILifeBlock"/>
                    <var name="left" type="ILifeBlock"/>
                    <var name="right" type="ILifeBlock"/>
                    <var name="lowerLeft" type="ILifeBlock"/>
                    <var name="lowerMiddle" type="ILifeBlock"/>
                    <var name="lowerRight" type="ILifeBlock"/>
                </variables>
                <script>
                    // Stop, if currently running.
                    if (sRunning)
                    {
                        sRunning = false;
                    }

                    // Hide, if currently showing.
                    ILifeGrid.hide();

                    // Set vars.
                    mX = x;
                    mY = y;
                    mWidth = width;
                    mHeight = height;
                    mHeaderHeight = (&STD_PADDING; * 2) + (&TEXT_OFFSET; * 2) +
                        _text_height(&HEADER_FONT_SIZE;, &HEADER_FONT_STYLE;,
                            &_FONT_FACE_SYSTEM;);

                    // Calculate and normalize rows and columns.
                    mRows = (height - &STD_PADDING; - mHeaderHeight) / boxHeight;
                    mCols = (width - &STD_PADDING;) / boxWidth;
                    if (mRows &_GT; &MAX_ROWS;)
                    {
                        mRows = &MAX_ROWS;;
                    }
                    else if (mRows &_LT; &MIN_ROWS;)
                    {
                        mRows = &MIN_ROWS;;
                    }
                    if (mCols &_GT; &MAX_COLS;)
                    {
                        mCols = &MAX_COLS;;
                    }
                    else if (mCols &_LT; &MIN_COLS;)
                    {
                        mCols = &MIN_COLS;;
                    }

                    // First pass: Create and load the block array.
                    _resizeArray(mBlocks, mRows, mCols);
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            mBlocks[rowCtr][colCtr] = _createInstance("LifeBlock");
                        }
                    }

                    // Create the timer source and timers
                    mTimers = _createInstance("TimerSource");
                    mTimers.init(mRows * mCols);
                    mTimers.addTimer(&RECALC;, &TICK_TIME;);
                    mTimers.addTimer(&UPDATE;, &TICK_TIME;);

                    // Determine offsets for the grid.
                    topOffset = mHeaderHeight + &STD_PADDING;;
                    if ((height - topOffset) &_GT; (mRows * boxHeight))
                    {
                        topOffset = mHeaderHeight +
                            ((height - topOffset - (mRows * boxHeight)) / 2);
                    }
                    leftOffset = &STD_PADDING;;
                    if (width &_GT; (mCols * boxWidth))
                    {
                        leftOffset = ((width - (mCols * boxWidth)) / 2);
                    }

                    // Second pass: Initialize the block array.
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            // Are we on the first row?
                            if (rowCtr == 0)
                            {
                                yPos = topOffset;
                                // Are we on the first column?
                                if (colCtr == 0)
                                {
                                    upperLeft =  mBlocks[mRows - 1][mCols - 1];
                                    upperMiddle = mBlocks[mRows - 1][colCtr];
                                    upperRight = mBlocks[mRows - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][mCols - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[rowCtr + 1][mCols - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][colCtr + 1];
                                    xPos = leftOffset;
                                }
                                // Are we on the last column?
                                else if (colCtr == mCols - 1)
                                {
                                    upperLeft =  mBlocks[mRows - 1][colCtr - 1];
                                    upperMiddle = mBlocks[mRows - 1][colCtr];
                                    upperRight = mBlocks[mRows - 1][0];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][0];
                                    lowerLeft = mBlocks[rowCtr + 1][colCtr - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][0];
                                }
                                // We are on a middle column.
                                else
                                {
                                    upperLeft =  mBlocks[mRows - 1][colCtr - 1];
                                    upperMiddle = mBlocks[mRows - 1][colCtr];
                                    upperRight = mBlocks[mRows - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[rowCtr + 1][colCtr - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][colCtr + 1];
                                }
                            }
                            // Are we on the last row?
                            else if (rowCtr == mRows - 1)
                            {
                                // Are we on the first column?
                                if (colCtr == 0)
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][mCols - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][mCols - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[0][mCols - 1];
                                    lowerMiddle = mBlocks[0][colCtr];
                                    lowerRight = mBlocks[0][colCtr + 1];
                                    xPos = leftOffset;
                                }
                                // Are we on the last column?
                                else if (colCtr == mCols - 1)
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][colCtr - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][0];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][0];
                                    lowerLeft = mBlocks[0][colCtr - 1];
                                    lowerMiddle = mBlocks[0][colCtr];
                                    lowerRight = mBlocks[0][0];
                                }
                                // We are on a middle column.
                                else
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][colCtr - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[0][colCtr - 1];
                                    lowerMiddle = mBlocks[0][colCtr];
                                    lowerRight = mBlocks[0][colCtr + 1];
                                }
                            }
                            // We are on a middle row.
                            else
                            {
                                // Are we on the first column?
                                if (colCtr == 0)
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][mCols - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][mCols - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[rowCtr + 1][mCols - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][colCtr + 1];
                                    xPos = leftOffset;
                                }
                                // Are we on the last column?
                                else if (colCtr == mCols - 1)
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][colCtr - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][0];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][0];
                                    lowerLeft = mBlocks[rowCtr + 1][colCtr - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][0];
                                }
                                // We are on a middle column.
                                else
                                {
                                    upperLeft =  mBlocks[rowCtr - 1][colCtr - 1];
                                    upperMiddle = mBlocks[rowCtr - 1][colCtr];
                                    upperRight = mBlocks[rowCtr - 1][colCtr + 1];
                                    left = mBlocks[rowCtr][colCtr - 1];
                                    right = mBlocks[rowCtr][colCtr + 1];
                                    lowerLeft = mBlocks[rowCtr + 1][colCtr - 1];
                                    lowerMiddle = mBlocks[rowCtr + 1][colCtr];
                                    lowerRight = mBlocks[rowCtr + 1][colCtr + 1];
                                }
                            }

                            // Init the block component.
                            mBlocks[rowCtr][colCtr].init(
                                xPos, yPos, boxWidth, boxHeight,
                                upperLeft, upperMiddle, upperRight,
                                left, right, lowerLeft, lowerMiddle, lowerRight);

                            // Add the timer listener.
                            mTimers.addTimerListener(mBlocks[rowCtr][colCtr]);

                            // Increment positions for next block.
                            xPos = xPos + boxWidth;
                        }
                        // Increment positions for next block.
                        yPos = yPos + boxHeight;
                    }

                    // Select the first block. (Could change to select middle block.)
                    mSelectedRow = 0;
                    mSelectedCol = 0;
                    mBlocks[mSelectedRow][mSelectedCol].select();

                    // Update.
                    updateAllBlocks();
                </script>
            </function>
            <!--
                Displays the grid.
            -->
            <function name="ILifeGrid.show" type="void">
                <variables>
                    <var name="rowCtr" type="int"/>
                    <var name="colCtr" type="int"/>
                </variables>
                <script>
                    // Show the background and header
                    sGridBackground = true;
                    sGridHeader = true;

                    // Show all the blocks
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            sGridBlocks[rowCtr][colCtr] = true;
                        }
                    }

                    // Update (in case anything has changed).
                    updateAllBlocks();
                </script>
            </function>
            <!--
                Hides the grid.
            -->
            <function name="ILifeGrid.hide" type="void">
                <variables>
                    <var name="rowCtr" type="int"/>
                    <var name="colCtr" type="int"/>
                </variables>
                <script>
                    // Hide the background and header
                    sGridBackground = false;
                    sGridHeader = false;

                    // Hide all the blocks
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            sGridBlocks[rowCtr][colCtr] = false;
                        }
                    }
                </script>
            </function>
            <!--
                Puts the grid into running mode.
            -->
            <function name="ILifeGrid.start" type="void">
                <script>
                    mGeneration = 0;
                    sRunning = true;

                    // Update.
                    updateAllBlocks();
                </script>
            </function>
            <!--
                Puts the grid into edit mode. (Default.)
            -->
            <function name="ILifeGrid.stop" type="void">
                <script>
                    sRunning = false;

                    // Update.
                    updateAllBlocks();
                </script>
            </function>
            <!--
                Sets all the blocks on the grid to dead.
            -->
            <function name="ILifeGrid.clearGrid" type="void">
                <variables>
                    <var name="rowCtr" type="int"/>
                    <var name="colCtr" type="int"/>
                </variables>
                <script>
                    // Stop, if currently running.
                    ILifeGrid.stop();

                    // Set all the blocks to dead
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            mBlocks[rowCtr][colCtr].setAlive(false);
                        }
                    }

                    // Update.
                    updateAllBlocks();
                </script>
            </function>
            <!--
                Selects the block component at the specified row and column.
            -->
            <function name="ILifeGrid.selectBlock" type="void">
                <parameters>
                    <var name="row" type="int"/>
                    <var name="column" type="int"/>
                </parameters>
                <script>
                    // Is the block already selected?
                    if (mSelectedRow != row || mSelectedCol != column)
                    {
                        // Are we in edit mode?
                        if (!sRunning)
                        {
                            // Deslect currently selected block.
                            mBlocks[mSelectedRow][mSelectedCol].deselect();
                            updateBlock(mSelectedRow, mSelectedCol);

                            // Select the new block.
                            mBlocks[row][column].select();
                            updateBlock(row, column);
                        }
                        // Cache new selected row/col values.
                        mSelectedRow = row;
                        mSelectedCol = column;
                    }
                </script>
            </function>
            <!--
                Toggles alive value of the block component at the specified row
                and column.
            -->
            <function name="ILifeGrid.toggleBlock" type="void">
                <parameters>
                    <var name="row" type="int"/>
                    <var name="column" type="int"/>
                </parameters>
                <script>
                    // Toggle alive of block.
                    mBlocks[row][column].setAlive(!mBlocks[row][column].getAlive());
                    updateBlock(row, column);
                </script>
            </function>
            <!--
                (Private) Updates the block component at the specified row and column.
            -->
            <function name="updateBlock" type="void">
                <parameters>
                    <var name="row" type="int"/>
                    <var name="column" type="int"/>
                </parameters>
                <script>
                    mBlocks[row][column].update();
                </script>
            </function>
            <!--
                (Private) Updates all block components in the grid.
            -->
            <function name="updateAllBlocks" type="void">
                <variables>
                    <var name="rowCtr" type="int"/>
                    <var name="colCtr" type="int"/>
                </variables>
                <script>
                    // Update all blocks
                    for (rowCtr = 0;rowCtr &_LT; mRows;rowCtr++)
                    {
                        for (colCtr = 0;colCtr &_LT; mCols;colCtr++)
                        {
                            mBlocks[rowCtr][colCtr].update();
                        }
                    }
                </script>
            </function>
        </functions>

        <script>

        </script>

        <states>
            <state var="sGridBackground">
                <transition value="true">
                    <display>
                        <!-- Background. -->
                        <box>
                            <x><eval>mX</eval></x>
                            <y><eval>mY</eval></y>
                            <width><eval>mWidth</eval></width>
                            <height><eval>mHeight</eval></height>
                            <fg>&COLOR_GRID_BG;</fg>
                            <bg>&COLOR_GRID_BG;</bg>
                        </box>
                    </display>
                </transition>
            </state>

            <state var="sGridHeader">
                <transition value="true">
                    <display>
                        <!-- Header. -->
                        <box>
                            <x><eval>mX + &STD_PADDING;</eval></x>
                            <y><eval>mY + &STD_PADDING;</eval></y>
                            <width><eval>mWidth - (&STD_PADDING; * 2)</eval></width>
                            <height><eval>mHeaderHeight - (&STD_PADDING; * 2)</eval></height>
                            <fg>&COLOR_HEADER_BG;</fg>
                            <bg>&COLOR_HEADER_BG;</bg>
                            <!-- Header Text. -->
                            <label>
                                <text>
                                    <eval>
                                        _strcat("&GRID_HEADER_TEXT_BEFORE;",
                                            mGeneration,
                                            "&GRID_HEADER_TEXT_AFTER;")
                                    </eval>
                                </text>
                                <x>&TEXT_OFFSET;</x>
                                <y>&TEXT_OFFSET;</y>
                                <fg>&COLOR_HEADER_TEXT;</fg>
                                <size>&HEADER_FONT_SIZE;</size>
                                <style>&HEADER_FONT_STYLE;</style>
                            </label>
                        </box>
                    </display>
                </transition>
            </state>

            <state var="sGridBlocks" index="*, *">
                <transition value="true">
                    <display>
                        <!-- Show a block. -->
                        <display-instance>
                            <instance>
                                <eval>
                                    mBlocks[_state_index(0)][_state_index(1)]
                                </eval>
                            </instance>
                        </display-instance>
                    </display>
                    <events>
                        <!--
                            Fired when a block is clicked.
                        -->
                        <event name="ILifeBlock.onClick">
                            <instance>
                                <eval>
                                    mBlocks[_state_index(0)][_state_index(1)]
                                </eval>
                            </instance>
                            <script>
                                // Are we in edit mode?
                                if (!sRunning)
                                {
                                    // Select the block.
                                    ILifeGrid.selectBlock(_state_index(0), _state_index(1));
                                    // Toggle the block.
                                    ILifeGrid.toggleBlock(_state_index(0), _state_index(1));
                                }
                            </script>
                        </event>
                    </events>
                </transition>
            </state>

            <state var="sRunning">
                <transition value="false">
                    <display>
                        <!-- Movement key event handlers. -->
                        <box>
                            <event name="onSelect">
                                <accelerators>
                                    <key>LEFT</key>
                                </accelerators>
                                <script>
                                    // Select the block to the left?
                                    if (mSelectedCol &_GT; 0)
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow, mSelectedCol - 1);
                                    }
                                    // Wrap around and select the block on the far right.
                                    else
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow, mCols - 1);
                                    }
                                </script>
                            </event>
                        </box>
                        <box>
                            <event name="onSelect">
                                <accelerators>
                                    <key>RIGHT</key>
                                </accelerators>
                                <script>
                                    // Select the block to the right?
                                    if (mSelectedCol &_LT; mCols - 1)
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow, mSelectedCol + 1);
                                    }
                                    // Wrap around and select the block on the far left.
                                    else
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow, 0);
                                    }
                                </script>
                            </event>
                        </box>
                        <box>
                            <event name="onSelect">
                                <accelerators>
                                    <key>UP</key>
                                </accelerators>
                                <script>
                                    // Select the block above?
                                    if (mSelectedRow &_GT; 0)
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow - 1, mSelectedCol);
                                    }
                                    // Wrap around and select the block on the bottom.
                                    else
                                    {
                                        ILifeGrid.selectBlock(mRows - 1, mSelectedCol);
                                    }
                                </script>
                            </event>
                        </box>
                        <box>
                            <event name="onSelect">
                                <accelerators>
                                    <key>DOWN</key>
                                </accelerators>
                                <script>
                                    // Select the block below?
                                    if (mSelectedRow &_LT; mRows - 1)
                                    {
                                        ILifeGrid.selectBlock(mSelectedRow + 1, mSelectedCol);
                                    }
                                    // Wrap around and select the block on the top.
                                    else
                                    {
                                        ILifeGrid.selectBlock(0, mSelectedCol);
                                    }
                                </script>
                            </event>
                        </box>
                    </display>
                    <script>
                        // Stop timers.
                        mTimers.stop();
                        // Show selected block as selected.
                        mBlocks[mSelectedRow][mSelectedCol].select();
                    </script>
                </transition>
                <transition value="true">
                   <events>
                        <!--
                            Timer component event handler. onTick is Fired after
                            all listeners have been serviced for a single tickID.
                        -->
                        <event name="ITimerSource.onTick">
                            <instance><eval>mTimers</eval></instance>
                            <parameters>
                                <var name="timerID" type="int"/>
                            </parameters>
                            <script>
                                // Update header?
                                if (timerID == &UPDATE;)
                                {
                                    mGeneration++;
                                    _clear_state(sGridHeader);
                                    sGridHeader = sGridHeader;
                                }
                            </script>
                        </event>
                    </events>
                    <script>
                        // Start timers.
                        mTimers.start();
                        // Show selected block as not selected.
                        mBlocks[mSelectedRow][mSelectedCol].deselect();
                    </script>
                </transition>
            </state>
        </states>

    </component>
</ujml>
Copyright (c) 2000-2007 UIEvolution, Inc. All rights reserved.
What do you think about this topic? Send feedback!