Table of Contents
Views are the fundamental visible elements of OpenLaszlo applications. Anything that is
displayed on the canvas is a <view>
or extends the view class.
Visually, a <view>
is a rectangular
container. As such it has a height, a width, and a placement, which is denoted by the x
and y values of its upper left corner. Views can have background colors, although by
default they are transparent. Transparent views can contain arbitrarily shaped images.
Thus although views are rectangular, OpenLaszlo applications can have virtually any
appearance.
Logically, views are objects that act as containers. Views may contain other views, called subviews or child views, and may be associated with resources such as images, audio or video files, and Flash Player files in .swf format. Thus although a view usually has a visual representation on the canvas, it is also possible to have, for example, a view of zero width and zero height that plays, for example, an audio file.
Example 26.1. Simple view
<canvas
height
="50
" width
="100%
">
<view
width
="50
" height
="50
" bgcolor
="red
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Example 26.2. Invisible view
<canvas
height
="50
" width
="100%
">
<view
height
="20
" width
="20
" clickable
="true
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The following example shows that the view, although invisible, is indeed present. To see that this is so, click in the upper left corner.
Example 26.3. Clicking on invisible view
<canvas
width
="100%
" height
="30
">
<view
height
="20
" width
="20
" onclick
="message.setAttribute('text', 'howdy')
"/>
<text
id
="message
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
A view is only visible if it has a color or an image assigned to it, and if the height and width are greater than zero. For example, the following code displays only two images even though four views are defined. The second and third views exist but they are completely transparent. The second has no color assigned to it and the third has zero width. They still, however, affect the arrangement of the other two views.
Example 26.4. Invisible views affect placement
<canvas
height
="60
" width
="100%
">
<view
width
="50
" height
="50
" bgcolor
="red
"/>
<view
width
="50
" height
="50
"/>
<view
width
="0
" height
="50
" bgcolor
="blue
"/>
<view
resource
="../images/logo.png
"/>
<simplelayout
axis
="x
" spacing
="5
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Aside from the x and y axes, there is also a z axis in the OpenLaszlo view hierarchy. Two sibling
views will overlap; the latter (in lexical order of the LZX code) will appear on top of
the former. This order can be changed using the bringToFront()
and sendToBack()
methods:
Example 26.5. Simple layout
<canvas
height
="100
" width
="100%
">
<view
bgcolor
="red
" width
="50
" height
="50
" onclick
="this.bringToFront()
"/>
<view
bgcolor
="blue
" width
="50
" height
="50
" x
="20
" y
="20
"/>
<view
bgcolor
="green
" width
="50
" height
="50
" x
="40
" y
="40
" onclick
="this.sendToBack()
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
There are also methods such as sendBehind()
and sendInFrontOf()
, that allow you to move a view in
the z-axis more precisely, relative to a specified view:
Example 26.6. Moving views along z axis
<canvas
height
="100
" width
="100%
">
<view
bgcolor
="red
" id
="red
" width
="50
" height
="50
" onclick
="this.sendInFrontOf(blue)
"/>
<view
bgcolor
="blue
" id
="blue
" width
="50
" height
="50
" x
="20
" y
="20
" onclick
="this.sendInFrontOf(green)
"/>
<view
bgcolor
="green
" id
="green
" width
="50
" height
="50
" x
="40
" y
="40
" onclick
="this.sendBehind(red)
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Views can also be contained within other views, allowing you to create complex visual elements. Each parent view can have any number of children, and each child view is positioned relative to the top-left corner of its parent, as shown here:
Example 26.7. Views containing other views
<canvas
height
="200
" width
="100%
">
<view
bgcolor
="red
" x
="50
" y
="50
" width
="100
" height
="100
">
<view
bgcolor
="blue
" width
="50
" height
="50
"/>
<view
bgcolor
="yellow
" x
="50
" y
="50
" width
="60
" height
="105
">
<view
width
="50
" height
="50
" bgcolor
="green
"/>
</view
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Each child view has one and only one parent view. The relationship between parent and child views is examined below and in later chapters.
If no width and height are actually defined for a view, then it adopts the width and
height of the bounding box of its subviews. The example above also shows, however, that
the width and height of a view can be different than the dimensions of the bounding box
of its child views. The 'yellow' view is not clipped even though it lies outside the
boundary of its parent. If clipping is desired, however, then the attribute
clip="true"
can be added to the parent:
Example 26.8. Using the "clip" attribute
<canvas
height
="150
" width
="100%
">
<view
bgcolor
="red
" x
="50
" y
="50
" width
="100
" height
="100
" clip
="true
">
<view
bgcolor
="blue
" width
="50
" height
="50
"/>
<view
bgcolor
="yellow
" x
="50
" y
="50
" width
="60
" height
="105
">
<view
width
="50
" height
="50
" bgcolor
="green
"/>
</view
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
As stated above, views don't need to display an image or color to affect other views.
These types of views are referred to as "blank views". In fact, this technique of using
blank views to group others views is used extensively in the sample applications. The
code below shows what happens when bgcolor="red"
is removed from the
outermost view.
Example 26.9. blank view
<canvas
height
="200
" width
="100%
">
<view
x
="50
" y
="50
" width
="100
" height
="100
">
<view
bgcolor
="blue
" width
="50
" height
="50
"/>
<view
bgcolor
="yellow
" x
="50
" y
="50
" width
="60
" height
="105
">
<view
width
="50
" height
="50
" bgcolor
="green
"/>
</view
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The fact that a view can be assigned different dimensions than the bounding box of its subviews is taken advantage of by other elements within OpenLaszlo such as constraints (Chapter 27, Constraints) and layouts (Chapter 17, Layout and Design).
To illustrate this point, the following example has two views with identical
dimensions and subviews. The only difference in their code is that the top view has a <simplelayout>
and the second view has a <stableborderlayout>
. The <simplelayout>
ignores the
width of the parent, while the <stableborderlayout>
stretches the middle subview so that the combined width of all three subviews matches
the width of their parent.
Don't worry if you don't understand how to use the layouts described below; layouts are fully explained in Chapter 17, Layout and Design. The crucial point to grasp is that a view can have different dimensions than the bounding box of its subviews. This fundamental property of the OpenLaszlo view system comes up in countless situations.
Example 26.10. Layouts and bounding box of subviews
<canvas
height
="100
" width
="100%
">
<view
bgcolor
="red
" width
="200
" height
="30
">
<view
bgcolor
="blue
" width
="30
" height
="30
"/>
<view
bgcolor
="yellow
" width
="30
" height
="30
"/>
<view
bgcolor
="blue
" width
="30
" height
="30
"/>
<simplelayout
axis
="x
" spacing
="0
"/>
</view
>
<view
bgcolor
="red
" width
="200
" height
="30
" y
="50
">
<view
bgcolor
="blue
" width
="30
" height
="30
"/>
<view
bgcolor
="yellow
" width
="30
" height
="30
"/>
<view
bgcolor
="blue
" width
="30
" height
="30
"/>
<stableborderlayout
axis
="x
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
A <tooltip>
is a child of a view that allows you to
show a floating descriptive message on that view. The parent view has to be clickable
for the tooltip to work. Setting clickable
to false will disable the tooltip.
Example 26.11. Using the <tooltip>
<canvas
height
="100
" layout
="axis:y; spacing: 10
">
<text
clickable
="true
">Mouse over a view to see the tooltip
<tooltip
>tooltip for a text view using the tooltip contents
</tooltip
>
</text
>
<button
text
="Button
">
<tooltip
text
="tooltip for a button using the tooltip text attribute
"/>
</button
>
<view
width
="30
" height
="30
" bgcolor
="red
" clickable
="true
">Mouse over a view to see the tooltip
<tooltip
>tooltip for a view using the tooltip contents
</tooltip
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007 - 2011 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
See the
tooltip
reference page for a complete description, including an example of a dynamic
<tooltip>
.
Starting with the canvas, each view has its own internal 2D coordinate system, with as you would expect, the horizontal axis named x and the vertical axis named y. The position of a view is calculated relative to its parent's coordinate system.
As view hierarchies can get complex, it's important to keep in mind, for any view:
where its origin is
units of measurement
its relationship to its parent's coordinate system
In the simple case where a view is, for example, the child of the canvas, understanding its origin and coordinate system is simple. Other cases can get rather subtle — as for example when a view's x or y value is a negative number, or when a parent view changes size. These cases are explored below.
To position the floating view over the clicked view, you can use the getAttributeRelative()
method of view to obtain the
x and y coordinates of the view relative to a view other than its parent. For example,
consider the case below:
Example 26.12. Relative positions
<canvas
width
="100%
" height
="100
">
<view
name
="parentView
" x
="10
" bgcolor
="blue
" height
="40
" width
="40
" oninit
="pview.setAttribute('text', ('parentview x is ' + x))
"/>
<view
name
="childView
" x
="35
" bgcolor
="yellow
" height
="20
" width
="20
" oninit
="cview.setAttribute('text', ('childview x is ' + x))
"/>
<text
x
="10
" y
="50
" id
="pview
"/>
<text
x
="10
" y
="70
" id
="cview
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
childView
's x
value is 35
, but
its x
value relative to
the canvas is 45
(because its parent,
parentView
, is already 10px in from the canvas's origin). To place
a view cover
that is a child of canvas on top of
childView
, give it an x
value of 45
,
because this is the same offset relative to cover
's parent (the
canvas) that childView
has relative to the canvas.
A view that has no width or height specified will be 0px wide by 0px high:
<view/>
Either dimension of a view can be set explicitly:
If a view's dimension is not explicitly set, and that view contains subviews (or has a resource attached), then the view will automatically scale to the extents of its contents or resource. In this case the yellow view will be 40px wide and 25px high:
<view bgcolor="yellow"> <view bgcolor="red" width="10" height="10" x="30" y="15"/> </view>
In the case above, the yellow view will resize as its contents resize and move. If a dimension had been set at any point then that axis would not resize. This is an important consideration if a nested view is to be moved while the application is running (e.g. if it is dragged by the user). The size of its parent will adjust as necessary:
Example 26.13. Resizing view
<canvas
height
="100
" width
="100%
">
<class
name
="dragBox
" onmousedown
="dragger.apply()
" onmouseup
="dragger.remove()
" clickable
="true
" width
="10
" height
="10
" bgcolor
="red
">
<dragstate
name
="dragger
"/>
</class
>
<view
bgcolor
="yellow
" y
="10
" x
="10
">
<dragBox
x
="30
" y
="10
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
To get around this problem (in the example of a view that is dragged), there are two solutions:
Limit the drag area of the view to its parents dimensions, and give its parent an explicit size.
Make the view that is dragged a child of the canvas, so that it is not embedded in the view hierarchy.
There is no way to unset a dimension, so that the view returns to resizing to its contents automatically.
Even if a view's dimensions are set explicitly, and the contents of the view are
larger than those dimensions, the view will remain the set
size. You can retrieve the computed width or
height using the measureWidth()
and measureHeight()
methods respectively.
<view bgcolor="yellow" width="30" height="100" clickable="true"> <handler name="onclick"> Debug.debug("Actual Width: %w", this.width); Debug.debug("Actual height: %w", this.height); Debug.debug("Measured Width: %w", this.measureWidth()); Debug.debug("Measured Height:%w ", this.measureHeight()); </handler> <view bgcolor="red" width="10" height="10" x="30" y="15"/> </view>
If a view attaches a resource (and doesn't have its dimensions set), then it sizes to
its resource. In this example, if someimg.jpg
is 70px wide by 30px
high, the view will also be 70px wide by 30px high:
<view resource="someimg.jpg"/>
In cases where the resource for a view is loaded at run-time (i.e. over HTTP), the view will be 0px wide by 0px high until the resource is loaded. This can cause unexpected behavior if other elements in your application are dependent on the size of the view in question. For example:
<canvas> <simplelayout axis="y" spacing="2"/> <view id="myImageView"/> <view width="100" height="20" bgcolor="yellow"/> <view width="100" height="20" bgcolor="red"/> <button x="10" y="110">Set Image Now! <handler name="onclick"> myImageView.setSource("someimage.jpg"); </handler> </button> </canvas>
At init time, the yellow view will be positioned at (0, 0), because
myImageView
will have dimensions of 0px wide by 0px high. When the
image is loaded (after the button gets clicked) myImageView
will
resize to accommodate the image, and display the image. Since
myImageView
and the other siblings are being acted on by <simplelayout>
, they will
all move down.
For more on the subject of assigning resources to views, see Chapter 18, Media Resources.
Consider the following example, which illustrates the effect of scaling a view's
coordinate system. On each click of the view, the value of the height
attribute diminishes by 10.
First let's look at a simple example that uses text, because this makes the effect more striking. As you click on the red rectangle, it shrinks, along with the text inside. But the font size does not change. The text is smaller relative to the canvas and to the computer screen, but not to its parent view.
Example 26.14. Simple scaling with text
<canvas
width
="100%
" height
="100
">
<font
src
="helmetb.ttf
" name
="helmet
"/>
<view
stretches
="both
" height
="100
" bgcolor
="red
" onclick
="this.animate('height', -10, 1000 , true )
">
<attribute
name
="aspect
" value
="${unstretchedwidth/unstretchedheight}
"/>
<attribute
name
="width
" value
="${ height * aspect}
"/>
<text
font
="helmet
" fontsize
="22
" resize
="true
">
This is some text
</text
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Here we have modified the example to further illustrate the same point. Notice how the width of the green view does not change, even as the view visibly shrinks.
Example 26.15. Simple scaling with text and colored view
<canvas
width
="100%
" height
="300
">
<font
src
="helmetb.ttf
" name
="helmet
"/>
<view
stretches
="both
" height
="100
" bgcolor
="red
" onclick
="this.animate('height', -10, 1000 , true ); message.addText('\ngreenview new width is ' + greenview.width)
">
<attribute
name
="aspect
" value
="${unstretchedwidth/unstretchedheight}
"/>
<attribute
name
="width
" value
="${ height * aspect}
"/>
<view
name
="greenview
" height
="100
" width
="80
" bgcolor
="green
"/>
<text
font
="helmet
" fontsize
="22
" resize
="true
">
This is some text
</text
>
</view
>
<text
id
="message
" y
="100
">Click on the green or red box
</text
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Every view has an internal registration point that is at
(0,0) by default, the upper left hand corner of the view. This point can be changed
using the xoffset
and yoffset
attributes. In short, the
offset attributes are applied to the registration point of the view. Now, the x and y of
this view is actually the position of its registration point within the view's parent
coordinate system. Here is a simple app that demonstrates this. See below for an
explanation of what's going on in this program.
Example 26.16. Offsets and registration point
<canvas
height
="250
" width
="100%
">
<!-- bouncing yellow square -->
<view
name
="bouncysquare
" x
="100
" y
="100
" bgcolor
="yellow
" xoffset
="20
" yoffset
="20
" width
="100
" height
="100
">
<animatorgroup
repeat
="Infinity
">
<animator
attribute
="xoffset
" duration
="1000
" to
="70
"/>
<animator
attribute
="xoffset
" duration
="1000
" to
="20
"/>
</animatorgroup
>
<animatorgroup
repeat
="Infinity
">
<animator
attribute
="yoffset
" duration
="500
" to
="70
"/>
<animator
attribute
="yoffset
" duration
="500
" to
="20
"/>
</animatorgroup
>
</view
>
<!-- Crosshairs constrained to x and y coordinates of the yellow square and intersecting at its registration point -->
<view
x
="${parent.bouncysquare.x}
" width
="1
" height
="100%
" bgcolor
="black
"/>
<view
y
="${parent.bouncysquare.y}
" width
="100%
" height
="1
" bgcolor
="black
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007 - 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The reason that the intersection point does not move is that the parent view (in
this case the canvas) is placing the colored view at that point, and that point does not
change. It is only the xoffset
and yoffset
that
are changing, not the x
and y
of the colored view.
Views rotate around the registration point. By default, xoffset
and yoffset
values are both zero and the registration point is in the
upper left corner of each view. Offsets allow you to change the rotation point. In the
example below, the pivot point of the red square is its upper left corner; the pivot
point of the blue square is its center (where x and y are set to "20").
Example 26.17. Simple offsets
<canvas
height
="100
" width
="100%
">
<view
x
="60
" y
="60
" height
="40
" width
="40
" bgcolor
="red
" onclick
="this.rotate.doStart()
">
<animator
name
="rotate
" attribute
="rotation
" to
="45
" duration
="500
" start
="false
" relative
="true
"/>
</view
>
<view
x
="60
" y
="60
" height
="40
" width
="40
" bgcolor
="blue
" xoffset
="20
" yoffset
="20
" onclick
="this.rotate.doStart()
">
<animator
name
="rotate
" attribute
="rotation
" to
="45
" duration
="500
" start
="false
" relative
="true
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Offsets allow the view to be placed relative to the point (xoffset
, yoffset
). (Otherwise the view is placed
using the view's top left corner as a reference point.) If a view has an offset, it will
affect how layouts position it relative to other views. See for example <constantboundslayout>
.
There are a variety of ways to set the position of a view. You can explicitly set its x and y values using tags; you can constrain the x and y values to values of other attributes, including those contained in a dataset, you can use layouts which "let the system" determine a view's position, or you can change the position at runtime by using script.
Declaratively
Using absolute x and y values
Using constraints
Using path constraints
Using layouts
Programmatically
You can position views using absolute x and y coordinates, and the view will be positioned relative to its parent's origin:
Example 26.18. Absolute positioning
<canvas
width
="100%
">
<view
bgcolor
="yellow
" width
="300
" height
="300
" x
="15
" y
="20
">
<view
bgcolor
="red
" width
="20
" height
="20
" x
="25
" y
="75
"/>
<view
bgcolor
="blue
" width
="20
" height
="20
" x
="75
" y
="200
"/>
<view
bgcolor
="green
" width
="20
" height
="20
" x
="50
" y
="50
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
You can also use constraints to position views. In the example below, the red view's position is set absolutely, the blue view's x and y positions are constrained to a function of the red view's coordinates.
Example 26.19. Using constraintes to position views
<canvas
width
="100%
">
<view
bgcolor
="yellow
" width
="300
" height
="300
">
<attribute
name
="someXValue
" type
="number
" value
="50
"/>
<view
bgcolor
="red
" name
="red
" width
="20
" height
="20
" x
="$once{20 + 5}
" y
="$once{70 + 5}
"/>
<view
bgcolor
="blue
" width
="20
" height
="20
" x
="${parent.red.y}
" y
="${parent.red.x}
"/>
<view
bgcolor
="green
" width
="20
" height
="20
" x
="${parent.someXValue}
" y
="${this.x}
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
In the example above,
The red x
and y
coordinates are
constrained to mathematical expressions (20+5 and 70+5 respectively).
The blue view's x
and y
coordinates are
constrained to the red view's y
and x
coordinates respectively.
The green view's x
and y
coordinates are
constrained to some arbitrary attribute value.
See Chapter 27, Constraints for more on constraint syntax.
The x and y values can be set to negative values. In the example below, clicking on the square causes successive views to appear and to move left or right. The parent square (teal color) expands to contain the blue and black squares, but not to contain the red and silver squares, which have negative x and y values.
Example 26.20. Positive and negative offsets
<canvas
width
="100%
" height
="250
" bgcolor
="gray
">
<view
x
="100
" y
="100
" bgcolor
="teal
">
<view
bgcolor
="red
" width
="20
" height
="20
" onclick
="this.animate('y' , -50 , 1000, true)
"/>
<view
bgcolor
="silver
" width
="20
" height
="20
" onclick
="this.animate('x' , -50 , 1000, true)
"/>
<view
bgcolor
="blue
" width
="20
" height
="20
" onclick
="this.animate('y' , 50 , 1000, true)
"/>
<view
bgcolor
="black
" width
="20
" height
="20
" onclick
="this.animate('x' , 50 , 1000, true)
"/>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Subpixel positioning gets blurry lines and images, with more positioning
possibilities. This makes it look worse for static images, and better for animation, and
for drawing sets of evenly spaced images where the average spacing isn't an integral
number of pixels. If you do something which causes a view to end up at a non-integer x
and y position, setting pixellock
to "true" will snap it the
nearest integer values.
pixellock
intercedes between the communication
between Laszlo and the flash player. It's important to have
setAttribute()
actually set the value you pass it, especially
for animators.
Note | |
---|---|
If you set |
Each view has a position in the view hierarchy, that is, the tree structure of objects in which each view has a parent, and, optionally, children and/or sibling views. In simple cases such as the following the relationship of parents and children is obvious from their position in the code.
Example 26.21. Simple view hierarchy
<canvas
height
="100
" width
="100%
">
<view
height
="100
" width
="100
" name
="grandparent
" bgcolor
="red
">
<view
height
="50
" width
="50
" name
="parent
" bgcolor
="green
">
<view
height
="30
" width
="30
" name
="child
" bgcolor
="blue
"/>
</view
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
However, things are usually more complicated, especially when views are created within classes. Views can be created or destroyed at runtime, and moreover a single line of code can cause the creation of an arbitrary number of views. In many cases there are, in effect, two hierarchies- the lexical hierarchy of views in the code, and the node hierarchy of objects that are created by the code.
LZX employs the terms parent and immediate parent to distinguish between a view's relationship in different hierarchies. These terms are explained in greater depth in later chapters, but here's a short preview.
Example 26.22. Parent and immediateparent
<canvas
height
="100
" width
="100%
">
<class
name
="mywindow
" onmousedown
="dragger.apply()
" onmouseup
="dragger.remove()
" bgcolor
="blue
">
<dragstate
name
="dragger
"/>
<attribute
name
="defaultplacement
" value
="mycontent
" type
="string
"/>
<view
name
="mycontent
" x
="10
" y
="10
" bgcolor
="white
" width
="${parent.width-20}
" height
="${parent.height-20}
">
</view
>
</class
>
<mywindow
id
="w
" width
="100
" height
="100
">
<text
>hello
</text
>
</mywindow
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The view that contains the text hello
has a parent
of w
and an immediateparent
of
w.mycontent
. Note that "mycontent" could be nested in other views and
it would still work. We call this ordering of objects the "node hierarchy." The term
"view hierarchy" is more intuitive, but "node hierarchy" is more correct. (Notice that
in the above example, "dragger" is a node, not a view)
If you're an experienced JavaScript programmer you will have seen this pattern before. When you see "immediateparent" in JavaScript, think "container".
Similarly, if you've looked at XAML, you may have seen that XAML distinguishes between the logical tree and the visual tree. The logical tree corresponds to the hierarchy as represented in the source (what we have sometimes called the source hierarchy). The visual hierarchy corresponds to the hierarchy as rendered.
Given this class definition:
Example 26.23. Simple placement
<canvas
height
="80
" width
="100%
">
<class
name
="myclass
">
<simplelayout
/>
<view
name
="content
"/>
<text
>label
</text
>
</class
>
<myclass
><text
placement
="content
">content1
</text
></myclass
>
<myclass
><text
placement
="content
">content2
</text
></myclass
>
<simplelayout
axis
="y
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
this source fragment:
<myclass><text placement="content">content1</text></myclass> <myclass><text placement="content">content2</text></myclass>
has the logical tree:
myclass (text "content1") myclass (text "content2")
and the visual tree:
myclass (view (text "content1")) (text "label") myclass (view (text "content2")) (text "label")
Thus parent
refers to the parent in the
logical tree. immediateparent
(in JavaScript) and placement
(in XML) refers to the parent
in the visual tree. Placement is similar to, but not the same as immediateparent. You
can think of them as meaning the same thing with different types, but just to be clear:
placement is a string which means: "find the view in my parent's children (or any
descendant) which has this name, and when I am created make me a child of that view."
immediateparent is then a reference to that view.
Placement is an instruction from a view to its parent about where it belongs within the parent's internal hierarchy. By default, this is interpreted to mean: 'find the subview with this name', but the parent is free to interpret it however it wants.
These concepts are explained in greater detail, and with several more examples, in Chapter 33, Extending Classes.
In LZX, the fundamental objects are called nodes. Nodes are abstract entities and as
such they have no visual representation. Views are the most common kind of node, and in
most cases when you need a container object, you should use a view even though a node would
work. In fact, although you can use <node>
s for most of the abstract infrastructure (dataset manipulation,
content management, polling, etc.), the compiler complains when putting datapointers and
datasets in nodes. Though a tag does exist for <node>
, new <node>
s must be created in script. See the <node>
entry in the reference
guide for details.
As discussed in later chapters, in situations when you are trying to squeeze out the last bit of performance, you may want to examine how much overhead there is in using a view versus a node (when there's no presentation associated with the element).
Sometimes it's important to understand the sequence that takes place when views are created. This is explained in depth in Appendix A, Understanding Instantiation, but here's a brief summary:
The evaluation of a view occurs in three phases:
Construction: The object representing the view is created, and attributes with constant initial values are filled in.
Instantiation: The attributes with
dynamic initial values are filled in (which includes the construction and
instantiation of any child views), the initialize()
method is executed, and the onconstruct
event is sent.
Initialization: The init()
method is executed and the oninit
event is sent.
Note that construction and instantiation occur sequentially, but that initialization
may be arbitrarily delayed, depending on the value of the initstage
attribute. Attributes with
dynamic initial values may not depend on other attributes with dynamic initial values, nor
on the initialize()
or init()
methods having been run.
When an view is built, subviews[]
is initialized to an empty
array. (In releases before OpenLaszlo 3.0 it was null.)
addSubview()
is like an event handler; it's a
protected method of view that is called when a view is added to its parent. You can't
call it directly, but you can override it. However, in most cases you will want to use
the onaddsubview
event instead.
If you have experience doing graphics programming, you may be interested in the following paragraph. Otherwise you can safely skip this topic.
The fundamental properties of a view are:
stretches
—which says whether to scale or not
and in which dimensions
unstretched{height,width}
—which are the
original's dimensions (and can be used to implement a scale factor)
{height,width}
—which will clip or scale
according to the setting of stretches
The OpenLaszlo system is equivalent to the Flash Player's, but syntactically OpenLaszlo
is closer to HTML/CSS standard (and would be equivalent if stretches
defaulted to both
instead of
none
).
Other systems define only a translation, or only a translation and scale, or allow an
arbitrary 3x2 or 3x3 transformation. OpenLaszlo is distinctive both in not defining a
translation (x
and y
position the bounds of the view
within its parent as well as defining a translation that precedes the rotate/scale, so it
can't be used for this), and in representing the matrix in terms of its ops (which leaves
some gaps, such as skew — but is much better for animation, which requires a much
heavier-duty symbolic mechanism in SVG).
The fact that resources aren't child views leads to some tension in the system, where designers expect them to be view-like, and there's a pull to make them view-like by adding rotation or translation to them that's independent of the view that embeds them, and to make it possible to retrieve their bounds. (This is largely independent from the fact that they're represented as ids instead of objects.)
Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.