-<ibex-doc title="The Ibex Reference" subtitle="Nitrogen Release" author="Adam Megacz" email="adam@ibex.org">
+<ibex-doc title="The Ibex Reference" subtitle="Nitrogen Release" author="Adam Megacz" email="adam@ibex.org" logo="ibex-logo.pdf">
<!-- ----------------------------------------------------------------------- -->
<section title="Introduction">
- **
- If you are reading the html version of this document and are
- thinking of printing it out, you might be interested in the nicely
- typeset <link url="reference.pdf" text="pdf version"/> produced
- with LaTeX.
- **
+
+ ** If you are reading the html version of this document and are **
+ ** thinking of printing it out, you might be interested in the nicely **
+ ** typeset <link url="reference.pdf" text="pdf version"/> produced **
+ ** with LaTeX. **
+
+ Ibex is a software platform based on the philosophy that the most
+ useful systems consist of both **statically typed** and
+ **dynamically typed** languages, working in concert.
+
+ <list>
+
+ - Statically typed languages (such as Java) are well suited for
+ high-performance, reliable, reusable code. Unfortunately
+ programs written in statically typed languages often take
+ longer to develop, and their commitment to a specific type
+ system makes interoperating with other languages cumbersome.
+
+ - Dynamically typed languages (such as JavaScript) typically
+ perform poorly (due to runtime checks and inadequate static
+ information for optimization), tend to admit more errors (due
+ to less static checking), and export APIs which are not
+ precisely defined (due to the huge number of possible
+ type/method combinations). However, writing programs in
+ dynamically typed languages is a much more rapid process, and
+ the implicit coercions in such languages make interoperability
+ between similar languages very easy.
+
+ </list>
+
+ The architectural incarnation of this philosophy is the Ibex Object
+ Model, a universal interface to dynamically typed languages. The
+ IOM serves as a common interface between statically typed languages
+ and dynamically typed languages both locally and over the network.
+
+ <section title="The Ibex Object Model">
- This document is a __reference__. It is not a
- __specification__ or a
- __tutorial__.
+ The Ibex Object Model consists of three primitive types:
+
+ <list>
+ - __number__ -- a floating point number
+ - __string__ -- a unicode string
+ - __boolean__ -- either [[true]] or [[false]]
+ </list>
+
+ From these primitives, more complex structures can be built from
+ two aggregate types:
+
+ <list>
+ - __array__ -- a collection of objects indexed by a non-negative integer
+ - __hash__ -- a collection of objects indexed by objects (often strings)
+ </list>
- This document does not guide the user gently through examples (as a
- tutorial would), and it doesn't provide enough detail and formality
- for a third party to construct a compatible re-implementation of the
- Ibex Core (as a specification would).
+ Any of the following actions can be performed on an object:
- Rather, the goal of this document is to completely describe every
- aspect of the environment that the Ibex Core provides to client
- applications, from the bottom up. If you want to be an Ibex expert,
- this is the right document to read. It is assumed that you are already
- familiar with XML and with either JavaScript or ECMAscript.
+ <list>
+ - __get(key)__ -- attempts to retrieve the object indexed by
+ [[key]]. Returns an object.
+
+ - __put(key, val)__ -- attempts to add object [[val]] with key
+ [[key]] to an object. Does not return a value.
+
+ - __call(args)__ -- attempts to call the object as if it were a
+ function. The [[args]] value is a list of arguments. May or
+ may not return a value.
+ </list>
- If you need to use or rely on some behavior you notice in the Ibex
- Core, but which is not clearly defined here, please post to <link
- url="http://lists.ibex.org/listinfo/users" text="the users mailing list"/>.
+ The keys of some objects may be enumerated by attempting to "call"
+ the object; the return value will be an array of the object's keys.
+
+ Finally, an object may be **coerced** to any of the three
+ primitive types, although this coercion may fail. Objects may
+ also be coerced to the **bytestream** type, which represents an
+ unbounded stream of octets. Dynamically typed code may not
+ explicitly manipulate bytestreams, although it can pass objects
+ to statically typed code which in turn coerces those objects to
+ bytestreams.
+ Any of the above operations may **throw** an exception, which is
+ itself an object.
+
+ Any entity in the statically typed world which supports these
+ operations may expose itself to the dynamically typed world.
+ Furthermore, it can expect that any values passed to it will support
+ all of the operations shown above.
+ </section>
+
+ <section title="Namespaces">
+ - relation to XML
+ - cover templates here with David's isomorphism?
+ </section>
+
+ <section title="Platforms Founded on the Ibex Object Model">
+
+ The remainder of this document describes the three major
+ systems founded on the Ibex Object Model:
+
+ <list>
+ - The Ibex User Interface
+ - The Ibex Persistent Storage Service
+ - The Ibex Mail Server
+ - IbexDoc
+ </list>
+
+ Currently, all four of these systems use Java as the statically
+ typed language and IbexScript (a derivitave of JavaScript) as
+ the dynamically typed language. However, since they interact
+ strictly via the Ibex Object Model, either component can be
+ rewritten in a different language.
+
+ </section>
+
<section title="Key Concepts">
<definition term="The Core">
</definition>
</section>
+</section>
+<section title="The Ibex User Interface">
<section title="Life Cycle of an Ibex Application">
<image url="lifecycle.pdf" caption="The Lifecycle of an Ibex Application"/>
A user typically begins an Ibex session by clicking on a link to
- an Ibex application. This link serves the {\tt launch.html} file
- to the user's browser, which in turn downloads the appropriate
- {\it Wildebeest} -- currently either an ActiveX Control
+ an Ibex application. This link serves the [[launch.html]] file
+ to the user's browser (1), which in turn downloads the appropriate
+ **Wildebeest** (2)-- currently either an ActiveX Control
(Win32/MSIE), XPInstaller (Mozilla), or Signed Applet (all
others).
The Wildebeest downloads the appropriate core for the user's
- machine and verifies its digital signature. It then launches the
- core, which downloads the UI (an [[.ibex]] archive), loads it,
- applies the [[main.t]] template (found in the archive), and
- renders it onto the screen, running any associated JavaScript
- code.
+ machine and verifies its digital signature (3). It then launches
+ the core, which downloads the UI (4), (an [[.ibex]] archive),
+ loads it, applies the [[main.t]] template (found in the archive),
+ and renders it onto the screen, running any associated JavaScript
+ code (5).
The user interacts with the application by clicking and moving the
- mouse, and by pressing keys on the keyboard. These actions trigger
- fragments of JavaScript code which are designated to handle events.
- This JavaScript code can then relay important information back to the
- server using XML-RPC or SOAP, or it can modify the structure and
- properties of the user interface to change its appearance, thereby
- giving feedback to the user.
+ mouse, and by pressing keys on the keyboard (5). These actions
+ trigger fragments of JavaScript code which are designated to
+ handle events. This JavaScript code can then relay important
+ information back to the server using XML-RPC or SOAP (5), or it
+ can modify the structure and properties of the user interface to
+ change its appearance, thereby giving feedback to the user.
The Ibex core quits when the last remaining surface has been destroyed.
of Ibex.
</section>
-</section>
<section title="The XML Template Representation">
A template (discussed in the next section) is an XML file which acts
as a blueprint for constructing a tree of boxes. We call this
- construction process **applying**, since unlike
- **instantiation** in object-oriented programming systems, you
- always apply a template to a pre-existing box, and you can apply
- multiple templates to the same box.
+ construction process **applying**, since unlike **instantiation** in
+ object-oriented programming systems, you always apply a template to
+ a pre-existing box, and you can apply multiple templates to the same
+ box.
Each XML tag corresponds to a single box, or to another template
which will be applied to that box. For example, a [[scrollbar]]
and written) from both static scripts as well as instance
scripts in a particular template. FIXME
</definition>
-
- </section>
+ </section>
<section title="Metadata">
</section>
<!-- ----------------------------------------------------------------------- -->
-<section title="Layout and Rendering">
+<section title="Rendering">
- <section title="Visual Components">
-
- Each box occupies a rectangular region on the surface. The visual
- appearance of a surface is created by rendering each box in its tree.
- Unless the [[clip]] attribute is [[false]], each box will
- clip its childrens' visual representations to its own, so that the
- children appear "confined to" the parent. Children are rendered after
- their parents so they appear "on top of" their parents.
-
- Each box has two major visual components, each with subcomponents:
+ FIXME: needs way, way, way more diagrams of nonrectangular boxes.
+
+ Each box occupies a region on the surface. The visual
+ appearance of a surface is created by rendering each box in its
+ tree. Unless the [[clip]] attribute is [[false]], each box will
+ clip its childrens' visual representations to its own, so that
+ the children appear "confined to" the parent. Children are
+ rendered after their parents so they appear "on top of" their
+ parents.
- FIXME: diagram
+ <heading title="Boxes Don't Have to Be Rectangular"/>
+
+ Until now we've tactily assumed that boxes are rectangular. In
+ fact, unlike its predecessor (XWT), Ibex boxes can be **any
+ shape at all**. We refer to the outline of a box as its path,
+ which may be composed of lines and curves (arcs and splines).
+ If the path is not set (or set to [[null]]), the box's path is
+ **implicitly** a rectangle.
+
+ A key step in understanding how Ibex works, and understanding
+ how operations on rectangular boxes generalize to arbitrary
+ boxes is to realize that "the path **is** the box". Just as a
+ rectangular box clips its children to the inside of the
+ rectangle, a circular box will clip its children to the inside
+ of the circle.
+
+ In fact, Ibex's integration of vector graphics with
+ constraint-based user interface layout runs quite deep -- boxes
+ which "contain" text are actually boxes whose outline path
+ **is** the actual letters of the text. This means that you can
+ assign children to a text-shaped box, and the children's
+ appearance will be cliped to the **inside** of the text letters.
+
+ The only time rectangular and non-rectangular boxes act
+ differently is when box packing takes place; when packing boxes,
+ Ibex only looks at the **bounding box** of a path (the smallest
+ rectangle that completely encloses the box's path). In the case
+ of rectangular boxes (which have not been rotated or sheared),
+ this bounding box happens to be exactly the same as the box's
+ path. So Ibex is actually treating these boxes the same, but
+ the chosen treatment favors rectangular boxes.
+
+ <section title="Visual Elements">
+
+ The appearance of a box consists of three visual elements: its
+ path, stroke, and fill.
- <definition term="path">
-
- A box's [[path]] consists of zero or more lines and curves.
- The path may be filled with a color, gradient, or texture, and
- may be stroked with a line of a given thickness and color. If
- the path is not specified, it defaults to the perimiter of the
- box. [**Note: Vector Graphics support (including the ability
- to set the [[path]] property to anything other than the
- default) is currently not implemented**].
-
- A path also has:
-
- <list>
- an associated [[strokecolor]], which is a color
-
- an associated [[strokewidth]], which is a number
- specifying the width of the stroke. [**Note: Vector
- Graphics support (including the [[strokewidth]]
- property) is currently not implemented**]
-
- a [[fill]], which is either a color, gradient, or
- texture
- </list>
- </definition>
-
- <definition term="text">
-
- Each box also has a single line of [[text]], whose
- appearance is determined by its:
-
- <list>
- associated [[font]], which can be any font supported by
- the <link url="http://www.freetype.org" text="FreeType2"/>
- library.
-
- an associated [[fontsize]] in **pixels**
-
- an associated [[textcolor]]
- </list>
- </definition>
-
- These eight components plus the size of a box fully specify its
- appearance. Every single box you see in Ibex is drawn only on the
- basis of these components and its size.
- </section>
+ <property name="path" type="string" default='""'>
+ A box's [[path]] consists of zero or more contours, each of
+ which consists of one or more lines, bezier curves (cubic or
+ quadradic), or generalized elliptic arcs. The grammar and
+ feature set supported are identical to that specified in <link
+ url="http://www.w3.org/TR/SVG11/paths.html" text="SVG 1.1,
+ section 8"/>.
+
+ One of the most common sources of frustration when working with
+ text representations of vector paths, or programs that manipulate
+ them, is making a mistake when setting a transform which causes
+ the entire path to be off the screen. Since no part of the path
+ is visible, you have no idea which direction it went! To minimize
+ the chance of this happening, and generally make dealing with
+ vectors a more enjoyable experience, Ibex always **recenters** a
+ path. When you set a box's path (either by writing to its
+ [[path]] or [[text]] properties), Ibex translates the entire path
+ so that it is lined up with the X and Y axes, as close to the
+ origin as possible, in the positive-X, positive-Y quadrant. Ibex
+ will note this translation by setting the box's [[transform]] to
+ the transformation used to do this. If you do not desire this
+ behavior, just set the [[transform]] back to the identity
+ transform.
+ </property>
+
+ <property name="stroke" type="string" default="clear">
+ The color with which to stroke the path. Ibex paths may
+ only be stroked with a single color, solid line (not
+ dashed), of "hairline width" (meaning that the line is never more than one
+ antialiased pixel wide no matter what magnification it is
+ viewed at).
+
+ This property can be set to a 5-character hex string
+ ([[#RGB]]), 7-character hex string ([[#RRGGBB]]),
+ 9-character hex string ([[#AARRGGBB]]), specifying the box's
+ hexadecimal color. Any other string is compared against the
+ <link url="http://www.color.org/ICC-1A_1999-04.PDF"
+ text="ICC"/> colors (the same set of color names supported
+ by SVG). If this property is set to [[null]], the stroke
+ color will be set to clear ([[#00000000]]).
+
+ Other vector formats (notably SVG and PDF) support "thick"
+ lines, dashed lines, lines stroked with a gradient or
+ texture, and an assortment of special caps and joins for
+ these thick lines (hairline lines do not need joins or
+ caps). Fortunately, all of these constructs can be
+ converted into **filled** paths rather easily, making it
+ possible for Ibex to support the same functionality with a
+ much simpler API (and more efficient rendering engine).
+ </property>
+
+ <property name="fill">
+ The graphic element with which to fill the path. This
+ property can be set to any of the values specified for
+ [[stroke]], as well as to a texture (an image) or a
+ gradient. Paths which self-intersect are filled according
+ to the SVG guidelines.
+
+ When an image (texture) is written to this property, the
+ box's [[minwidth]] and [[minheight]] properties will be
+ automatically set to the dimensions of the image (they can
+ be changed later if desired).
+ </property>
+ </section>
+
+ <section title="Text">
+
+ Ibex treats text exactly the same way it treats other paths.
+ Writing to the [[text]] property actually sets the box's path to
+ the outline of the rendered form of the text, and text is
+ subject to the same rotation, shearing, and scaling
+ transformations as all other boxes. You can even **read back**
+ the curves from which the text is composed by reading from the
+ [[path]] property (the string returned will be in SVG Path
+ syntax), modify it, and write it to the [[path]] property of
+ another box.
+
+ <property name="text" type="string" default='""'>
+ The box's text; writing [[null]] to this property sets it to
+ [[""]]. In order to help eliminate common chores when working
+ with text, Ibex will automatically take the following actions
+ when you write to the [[text]] property:
+ </property>
+
+ <list>
+ The text is converted to curves using the Freetype library,
+ and the resulting curve becomes the box's path.
+
+ If the box's [[strokecolor]] is [[null]], it is set to black
+ ([[#FF000000]]). When first created, a box has an invisible
+ stroke; automatically setting the stroke to a visible color
+ helps eliminate confusing errors. You can change the stroke
+ color back to clear after writing to the [[text]] property.
+
+ The box's [[aspect]] property is automatically set to the
+ correct aspect ratio for the chosen string in the chosen
+ font. This ensures that resizing will not warp the text.
+ </list>
+
+ <property name="font" type="stream" default=".ibex.ui.font.sansserif">
+ Fonts are rendered using the [[stroke]] assigned to the box,
+ using the font assigned to the [[font]] property. When an
+ object is written to this property, it is coerced to a stream which is interpreted using
+ the <link url="http://www.freetype.org" text="FreeType 2
+ library"/>, and the resulting font is used to render the box's
+ [[text]].
+
+ To choose the size of a font, just set the box's [[height]]
+ property to the desired height **in pixels**. Conversion
+ functions from points to pixels are available.
+ </property>
+ </section>
+
+ <section title="Transformations">
+ The [[transform]] property allows the user to specify an
+ arbitrary affine transformation to be applied to the box's path,
+ text, and children. The syntax and features supported are
+ identical to those described in <link
+ url="http://www.w3.org/TR/SVG11/coords.html" text="SVG 1.1,
+ section 7"/>, and include rotation, shearing, scaling, and
+ translation.
+
+ <property name="transform">
+ FIXME
+ </property>
+
+ One tricky part about transformations is their interaction with
+ box packing and dimension properties. A box's size properties
+ (such as [[minwidth]] or [[height]]) are **always** measured in
+ the box's own coordinate space (ie after applying the box's
+ [[transform]]). This means that the sum of the [[width]]s of a
+ box's children may not be equal to the parent box's [[width]],
+ even if the children appear (on screen) to completely fill its
+ width.
+
+ One other consequence of combining transformations with
+ constraint-based layout is that when a box is rotated, its width
+ and height are no longer completely independent (remember, the
+ box's width is measured in the rotated coordinate space). If a
+ box is turned at a 45 degree angle and then forced into a space
+ 10 pixels wide, enlarging the box's width will force a reduction
+ in its height (in order to cram it in the 10 pixel space). In
+ situations like this, Ibex will first look to the box's
+ [[aspect]], if explicitly set, and obey that. If the box's
+ [[aspect]] is unspecified, Ibex will use the ratio between the
+ box's [[minwidth]] and [[minheight]] to guide the tradeoff. If
+ either of these properties is [[0]], Ibex will simply attempt to
+ make the ratio as close to [[1:1]] as possible.
+
+ When we talk about a box's **bounding box**, we are referring to
+ the smallest rectangle in the **parent's** coordinate space
+ which completely encloses the child box's path. This is the
+ only time we will deal with the size of a child using a
+ coordinate space other than its own.
+ </section>
+
+ <section title="Layout Properties">
+
+ We will cover the layout algorithm in detail in the next section,
+ but we introduce the properties at play here and give an intuition
+ about their purpose.
+
+ <property name="packed" type="boolean" default="true">
+ The layout strategy for this box. If set to [[true]], the
+ box occupies no cells and is laid out independently of its
+ siblings.
+ </property>
+
+ <property name="zoom" type="boolean" default="false">
+ This property controls the strategy Ibex uses for changing the
+ box's width and height in response to layout constraints.
+
+ If [[zoom]] is set to [[false]] (the default), then the box's
+ [[path]] will be altered by multiplying all the vertices by a
+ scaling factor in order to make the path's bounding box meet
+ the required constraints. The box's [[transform]] will not be
+ affected, and the scaling of the box's children will not be
+ affected.
+
+ If [[zoom]] is set to [[true]], the box's [[path]] will not be
+ altered in response to layout constraints; rather, its
+ [[transform]] will be altered in order to "zoom in" or "zoom
+ out" and bring all of the path's vertices within the desired
+ region. Since the box's [[transform]] also applies to its
+ descendants, they too will be magnified or reduced.
+ </property>
+
+ <property name="shrink" type="boolean" default="false">
+ If set to [[true]], this box will shrink
+ (horizontally/vertically/both) to the smallest size allowed by
+ its children and the bounding box of its path.
+ </property>
+
+ <property name="x y" type="integer" default="varies">
+ If the box is a root box, writing to these properties moves
+ the surface; reading from them returns the position of the
+ surface.
+
+ On non-root boxes, writing to these properties is a shorthand
+ for adding a [["translate(x, y)"]] to the box's [[transform]].
+ Reading from these properties will return FIXME.
+ </property>
+
+ <property name="minwidth minheight" type="integer" default="0">
+ The desired minimum width and height. See the [[zoom]]
+ property for a description of how the box is altered to meet
+ these constraints.
+ </property>
+
+ <property name="maxwidth maxheight" type="integer" default="ibex.ui.maxdim">
+ The desired maximum width and height. See the [[zoom]]
+ property for a description of how the box is altered to meet
+ these constraints.
+ </property>
+
+ <property name="width height" type="integer">
+ When read, this is the current (width/height) of this box.
+ Writing to this property is equivalent to writing to
+ **both** the minimum and maximum (width/height).
+ </property>
+
+ <property name="cols rows" type="integer" default="0">
+ The number of (columns/rows) in which to lay out the children of this
+ box. If set to zero, the number of (columns/rows) is unconstrained.
+ Either [[rows]] or [[cols]] must be zero. If
+ [[0]] is written to [[cols]] when [[rows]] is
+ [[0]], the write is ignored. If a nonzero value is
+ written to [[cols]] when [[rows]] is nonzero,
+ [[rows]] is set to [[0]], and vice versa.
+ </property>
+
+ <property name="colspan rowspan" type="integer" default="1">
+ The number of (columns/rows) that this box spans within its parent.
+ </property>
+
+ <property name="aspect" type="float" default="0.0">
+ The width-to-height ratio constraint for this box; can be set
+ either as a floating point number ([[0.5]]) or a ratio
+ ([["1:2"]]). Setting this to [[0.0]] disables the ratio
+ constraint.
+
+ Note packed boxes always **shrink** in order to satisfy aspect
+ constraints, while unpacked boxes always **grow** in order to
+ satisfy them -- even if this means growing larger than the box's
+ parent.
+ </property>
+
+ <property name="visible" type="boolean" default="true">
+ If set to [[false]], this box will be rendered as if its
+ width and height were zero. If this is a root box, the
+ associated surface will be hidden.
+
+ When reading from this property, the value [[false]] will
+ be returned if this box **or any of its ancestors** is not
+ visible. Thus it is possible to write [[true]] to a box's
+ [[visible]] property and then read back [[false]].
+ </property>
+ </section>
- <section title="Size and Position">
+</section>
+
+<section title="Layout Algorithm">
The size and position of every box is determined by its
properties, its childrens' sizes, and its parent's size and
not the same thing as the property [[minwidth]], although they
are closely related.
- <heading title="The Size of the Root Box"/>
-
- When the user resizes a window, Ibex changes the root box's
- [[maxwidth]] and [[maxheight]] to match the size chosen by
- the user and then determines the root box's size using the same sizing
- rules it uses for other boxes.
-
- Ibex will always attempt to prevent the
- user from making the surface smaller than the root box's
- [[minwidth]] and [[minheight]]. If the [[hshrink]] or
- [[vshrink]] flag is set, Ibex will try to prevent the user from
- resizing the surface at all. However, not all platforms give Ibex
- enough control to do this.
-
- <image url="alignmentpoint.pdf" caption="The effect of alignment points on layout" width="3in"/>
-
- <heading title="The alignment point"/>
-
- When talking about positioning, we will often refer to the
- **alignment point**.
-
- If the [[align]] property is "[[center]]", then the
- alignment point is the center of the box.
-
- If the [[align]] property is "[[topleft]]",
- "[[bottomleft]]", "[[topright]]", or
- "[[bottomright]]", then the alignment point is
- corresponding corner of the box.
-
- If the [[align]] property is "[[top]]",
- "[[bottom]]", "[[right]]", or "[[left]]", then
- the alignment point is middle of the corresponding edge of the
- box.
-
<section title="Packing">
A grid of **cells** is created within the parent. If the
infinite number of columns. Either [[cols]] or [[rows]]
must be zero, but not both.
- If a child's [[visible]] property is [[false]], it does
- not occupy any cells (and is not rendered). Otherwise, each child
- occupies a rectangular set of cells [[child.colspan]] cells
- wide and [[child.rowspan]] cells high.
+ <heading title="Target Regions"/>
+
+ A box's target region is the portion of its parent which the
+ layout algorithm has determined that the box should occupy. A
+ box's target region is determined mainly by the value of its
+ [[pinned]] property:
+
+ <property name="pinned" type="box" default="null">
+ If a box's [[pinned]] property is [[null]], it is said to be
+ "unpinned" or "not pinned". In this case, the box's target
+ region will be the set of cells in its parent which it
+ occupies.
+
+ If a box's [[pinned]] region is set to some other box, then
+ this box's target region will be the projection of that
+ other box's actual dimensions and position, projected onto
+ this box's parent. The net effect is that the pinned box
+ will "track" the size and position of the box it is pinned
+ to. A box may not be pinned to one of its descendants, nor
+ may boxes be pinned in a cycle (A is pinned to B, B is
+ pinned to C, and C is pinned to A).
+ </property>
+
+ If a child's [[visible]] property is [[false]], it does not
+ occupy any cells (and is not rendered). If a box's [[pinned]]
+ property (described below) is non-[[null]], it does not occupy
+ any cells and is exempt from the packing process. Otherwise,
+ each child occupies a rectangular set of cells [[child.colspan]]
+ cells wide and [[child.rowspan]] cells high.
The Core iterates over the cells in the grid in the following
order: if [[rows]] is 0, the Core iterates across each column
before proceeding to the next row; otherwise rows come before
columns. At each cell, the Core attempts to place the **first
- remaining unplaced child's** top-left corner in that cell
- (with the child occupying some set of cells extending down and
- to the right of that cell). If the parent has a fixed number of
- columns and the child's [[colspan]] exceeds that limit, the
- child is placed in column zero regardless, but only occupies the
- available set of cells (it does not "hang off the end" of the
- box). <image url="layout.pdf" width="1in"/>
+ remaining unplaced, packed child's** top-left corner in that
+ cell (with the child occupying some set of cells extending down
+ and to the right of that cell). If the parent has a fixed
+ number of columns and the child's [[colspan]] exceeds that
+ limit, the child is placed in column zero regardless, but only
+ occupies the available set of cells (it does not "hang off the
+ end" of the box). <image url="layout.pdf" width="1in"/>
<pre>
<ui:box cols="3">
<ui:box id="4" />
<ui:box id="5" colspan="2" />
</ui:box>
-
-
-
</pre>
</section>
<section title="Constraining">
-
Each box's minimum width is computed recursively as the
maximum of:
<list>
Its [[minwidth]]
- The width of the box's [[text]] (after applying the
- box's [[transform]]) [**Note: Vector Graphics support
- (including the [[transform]] property) is currently not
- implemented**].
+ The width of its [[path]]
- The width of the box's path (after applying the box's
- [[transform]]) **if the box is [[packed]]**.
-
- The minimum width of the children in each row.
+ The sum of the widths of the bounding boxes enclosing its
+ children, when those children are sized to **their own**
+ minimum widths.
+
+ The box's minimum **height** multiplied by its [[aspect]],
+ if its aspect is not [[0]] (unspecified).
</list>
-
+
If a box's [[hshrink]] property is set to
[[true]], the box's maximum width is the same as its
minimum width; otherwise it is the box's
[[maxwidth]].
-
</section>
<section title="Placing">
-
- <section title="Packed Boxes">
+
+ <heading title="Target Origin"/>
+
+ Once the box's size and the size and position of its target
+ region have been computed, the box is placed relative to its
+ **target origin**, which is determined by by the [[origin]]
+ property:
+
+ <property name="origin" type="string" default="center">
+ Determines which corner of the box's target region should be
+ treated as the origin for layout purposes.
+
+ If the [[origin]] property is "[[center]]", then the
+ target origin is at the center of the target region.
+
+ If the [[origin]] property is "[[topleft]]",
+ "[[bottomleft]]", "[[topright]]", or "[[bottomright]]", then
+ the target origin is at the corresponding corner of the
+ target region.
+
+ If the [[origin]] property is "[[top]]", "[[bottom]]",
+ "[[right]]", or "[[left]]", then the target origin is middle
+ of the corresponding edge of the target region.
+ </property>
+
+ <property name="x y" type="number" default="0">
+ Determines the offset from the box's origin at which it will
+ be placed.
+ </property>
+
+ If the box's [[hshrink]] property is not set, it is expanded to
+ its maximum width, but no larger than its parent's width.
+
+ Finally, if the child has a nonzero [[aspect]], one of its
+ dimensions (either width or height) will **grow** in order to
+ ensure that [[width == height * aspect]]. This may cause the
+ child to exceed the paren't size.
+
+ <heading title="Non-Packed Boxes with a transform"/>
+
+ First, the coordinate space in which the child is positioned is
+ translated so that the origin coincides with the
+ corner/edge/center of the box's parent corresponding to the
+ child's [[align]] property. The child's [[transform]] attribute
+ is applied to the coordinate space, and the child is positioned
+ in this transformed space with its aligment point at the origin.
+
+ The following diagram may be helpful:
+
+ FIXME: diagram
+
+ <heading title="Packed Boxes"/>
+
+ Thoughout this section, when we refer to the [[minwidth]],
+ [[maxwidth]], or minimum width of a child box, we are referring
+ to the corresponding dimension of the child's **bounding box**
+ -- the smallest rectangle **in the parent's coordinate space**
+ that completely encloses the child's path.
Ibex formulates a set of constraints for placing a box's
**packed** children as follows:
<list>
- - A box's width can be no greater than the sum of the
+ A box's width can be no greater than the sum of the
columns it occupies
- - The sum of a set of colums cannot be smaller than the
+
+ The sum of a set of colums cannot be smaller than the
minimum width of a box that spans them.
- - The sum of the widths of the parents' columns will be at
+
+ The sum of the widths of the parents' columns will be at
least as large as the parent's width is (but possibly
larger).
</list>
prioritized from most important to least important:
<list>
- - (__Most Important__) The sum of all columns will be a close
+ (__Most Important__) The sum of all columns will be a close
to the parent's with as possible (ie as small as possible)
- - Ibex will attempt to make a set of columns no wider than
+
+ Ibex will attempt to make a set of columns no wider than
the [[maxwidth]] of a box spanning them.
- - (__Least Important__) Ibex will attempt to make all
- columns the same width.
+
+ Ibex will attempt to make all
+ columns the same width. (**least important**)
</list>
Each packed box is then placed within the set of cells that it
spans. Usually the box will exactly fill this rectangle; if it
- does not (due to [[maxwidth]] or minimum width constraints), the
- box's will be placed so that its alignment point coincides with
- the alignment point of that rectangle of cells.
- </section>
+ does not (due to [[maxwidth]], minimum width, or aspect
+ constraints), the box's will be placed so that its alignment
+ point coincides with the alignment point of that rectangle of
+ cells.
- <section title="Non-Packed Boxes">
- Each non-packed box is transformed according to the parent's
- [[transform]] property and then positioned so that its alignment
- point is [[(child.x, child.y)]] pixels from the corresponding
- edge/corner/center of its parent.
- </section>
-
- </section>
+ <heading title="The Size of the Root Box"/>
- <section title="Rendering">
-
- Boxes are rendered in a depth-first, pre-order traversal. Note that
- this may cause a non-packed box to overlap its siblings.
-
- <list type="ordered">
-
- If the box's [[transform]] property is non-null, the
- coordinate space is transformed accordingly for the rest of
- this phase and for the rendering of all children. [**Note:
- Vector Graphics support (including the [[transform]]
- property) is currently not implemented**].
-
- If the box is packed and has a non-[[null]] path, the
- path is translated such that the alignment point of the path's
- bounding box coincides with the box's alignment point (both
- alignment points are determined by the box's [[align]]
- property).
-
- If a box has a path, that path is filled with the color,
- gradient, or image specified by the [[fill]] property and
- stroked with the color and width specified by the
- [[strokecolor]] and [[strokewidth]] properties.
-
- If the box has a non-null [[text]] attribute,
- the text is rendered in [[font]] with size
- [[fontsize]] and color [[textcolor]]. The text is
- then translated such that the alignment point of the text's
- bounding box coincides with the box's alignment point (both
- alignment points are determined by the box's [[align]]
- property).
-
- The box's children are rendered (pre-order traversal).
-
- </list>
-
- </section>
-
+ When the user resizes a window, Ibex changes the root box's
+ [[maxwidth]] and [[maxheight]] to match the size chosen by
+ the user and then determines the root box's size using the same sizing
+ rules it uses for other boxes.
+
+ Ibex will always attempt to prevent the
+ user from making the surface smaller than the root box's
+ [[minwidth]] and [[minheight]]. If the [[hshrink]] or
+ [[vshrink]] flag is set, Ibex will try to prevent the user from
+ resizing the surface at all. However, not all platforms give Ibex
+ enough control to do this.
+
</section>
+</section>
+
<!-- ----------------------------------------------------------------------- -->
<section title="Box Properties">
meaning, which will be explained later. Each box's numeric
properties hold its **child boxes**.
- <section title="Rendering Properties">
-
- Every box has several special properties which control how it is
- drawn. In general, if you put an
- invalid value to a special property, no action will be taken -- the
- put will be ignored.
-
- <property name="strokecolor" type="string" default="clear">
-
- If the value is a 5-character hex string ([[#RGB]]),
- 7-character hex string ([[#RRGGBB]]), 9-character hex
- string ([[#AARRGGBB]]), the box's stroke color will be set
- to that color.
-
- If the value is one of the <link
- url="http://www.color.org/ICC-1A_1999-04.PDF"
- text="ICC"/> colors (the same set of color names
- supported by SVG), the stroke color be set to that color.
-
- If the value is [[null]], the stroke color will be set
- to clear ([[#00000000]]).
- </property>
-
- <property name="strokewidth" type="int" default="1">
- The width (in pixels) to stroke the path with.
- </property>
-
- <property name="fill">
- This property can be set to any of the values specified for
- [[strokecolor]].
- Alternatively, if the value written is an object, its stream
- will be read and interpreted as a PNG, GIF, or JPEG image,
- which will become the texture for this box, and the box's
- [[minwidth]] and [[minheight]] properties will be
- automatically set to the dimensions of the image.
- </property>
-
- <property name="path" type="string" default='""'>
- The box's path. The grammar and feature set supported are
- identical to that specified in <link
- url="http://www.w3.org/TR/SVG11/paths.html" text="SVG 1.1,
- section 8"/>.
- </property>
-
- <property name="text" type="string" default='""'>
- The box's text; writing [[null]] to this property sets it
- to [[""]].
- </property>
-
- <property name="textcolor" type="number" default="black">
- The color in which to render the font; accepts the same values as [[strokecolor]].
- </property>
-
- <property name="font" type="stream" default=".ibex.ui.font.sansserif">
- When an object is written to this property, its stream is read
- using the <link url="http://www.freetype.org" text="FreeType 2 library"/>,
- and the resulting font is used to render the
- box's [[text]].
- </property>
-
- <property name="fontsize" type="number" default="10">
- The size (in points) to render the text.
- </property>
-
- </section>
-
- <section title="Layout Properties">
-
- <property name="shrink" type="boolean" default="false">
- If set to [[true]], this box will shrink
- (horizontally/vertically/both) to the smallest size allowed by
- its children and the bounding box of its path.
- </property>
-
- <property name="x y" type="integer" default="varies">
- If the box is a root box, this is the (x/y)-coordinate of the
- surface; otherwise it is the distance between the parent's
- alignment point and the corresponding corner/edge/center of
- its parent.
- </property>
-
- <property name="minwidth minheight" type="integer" default="0">
- The desired minimum width and height.
- </property>
-
- <property name="maxwidth maxheight" type="integer" default="ibex.ui.maxdim">
- The desired maximum width and height.
- </property>
-
- <property name="width height" type="integer">
- When read, this is the current (width/height) of this box.
- Writing to this property is equivalent to writing to
- **both** the minimum and maximum (width/height).
- </property>
-
- <property name="cols rows" type="integer" default="0">
- The number of (columns/rows) in which to lay out the children of this
- box. If set to zero, the number of (columns/rows) is unconstrained.
- Either [[rows]] or [[cols]] must be zero. If
- [[0]] is written to [[cols]] when [[rows]] is
- [[0]], the write is ignored. If a nonzero value is
- written to [[cols]] when [[rows]] is nonzero,
- [[rows]] is set to [[0]], and vice versa.
- </property>
-
- <property name="colspan rowspan" type="integer" default="1">
- The number of (columns/rows) that this box spans within its parent.
- </property>
-
- <property name="align" type="string" default="center">
- Determines the box's alignment point for positioning its text,
- texture, path, and children.
- </property>
-
- <property name="visible" type="boolean" default="true">
- If set to [[false]], this box will be rendered as if its
- width and height were zero. If this is a root box, the
- associated surface will be hidden.
-
- When reading from this property, the value [[false]] will
- be returned if this box **or any of its ancestors** is not
- visible. Thus it is possible to write [[true]] to a box's
- [[visible]] property and then read back [[false]].
- </property>
-
- <property name="packed" type="boolean" default="true">
- The layout strategy for this box. If set to [[true]], the
- box occupies no cells and is laid out independently of its
- siblings.
- </property>
-
- </section>
-
<section title="Child Control Properties">
<property name="redirect" type="box" default="thisbox">
<property name="surface" type="" default="null">
- FIXME
If this box has a parent, this property returns
[[**parent**.surface]]; otherwise it returns null.
This property is a simple building block that the widget
windows.
</property>
- <property name="Maximized">
+ <property name="Maximized Minimized">
The value [[true]] is put to this property on the root box
- when the surface is maximized, and [[false]] when the surface
- is un-maximized. Reading from this value will return [[true]]
- if the surface is maximized and [[false]] if it is
- not. Putting [[true]] to this property will maximize the
- window, and putting [[false]] to this property will
- unmaximize the window.
+ when the surface is maximized/minimized, and [[false]] when
+ the surface is un-maximized/minimized. Reading from this value
+ will return [[true]] if the surface is maximized/minimized and
+ [[false]] if it is not. Putting [[true]] to this property will
+ maximize/minimize the window, and putting [[false]] to this
+ property will unmaximize/unminimize the window.
+
Note that not all platforms support maximization.
</property>
- <property name="Minimized">
- The value [[true]] is put to this property on the root box
- when the surface is minimized, and [[false]] when the surface
- is unminimized. Reading from this value will return [[true]]
- if the surface is minimized and [[false]] if it is
- not. Putting [[true]] to this property will minimize the
- window, and putting [[false]] will unminimize it.
- </property>
-
<property name="Close">
When the user attempts to close a surface, the value
[[true]] will be put to this property. Scripts may trap
property.
</property>
- <property name="icon">
- The surface's icon. This is usually displayed on the titlebar of a
- window. The value should be an object whose stream is a PNG image. Note
- that not all platforms support this property.
+ <property name="titlebar">
+ The surface's titlebar text and icon. If a string is written
+ to this property, the surface's titlebar text is set to that
+ string; if a stream yielding an image is written, the
+ surface's icon is set to that image. Note that not all
+ platforms support this property. Only ASCII characters
+ 0x20-0x7F are permitted.
</property>
- <property name="titlebar">
- The surface's titlebar text. Note that not all platforms support
- this property. Only ASCII characters 0x20-0x7F are permitted.
+ </section>
+
+ </section>
+
+
+<section title="Events">
+
+ Every execution of the Event Context begins with an event, which
+ consists of a key/value pair, and a mouse position, which consists of
+ an x and y coordinate. The possible keys are [[_Press[1-3]]],
+ [[_Release[1-3]]], [[_Click[1-3]]], [[_DoubleClick[1-3]]],
+ [[_Move]], [[_KeyPressed]], and [[_KeyReleased]].
+
+ Here are two example events:
+
+ An event is triggered by writing the key to the value on a box. This
+ triggers any trap handlers which may be present. Once these handlers
+ have executed, Ibex figures out which child of the current box contains
+ the mouse (taking into account that some boxes may cover up others)
+ and writes the key and value to that box. If none of the box's
+ children contain the mouse position, Ibex removes the leading
+ underscore from the key name and writes the value to
+ **that** property. Once all the traps on that property have
+ executed, the value is written to the box's parent.
+
+ Intuitively, Ibex delivers the underscored event to every box from the
+ root to the target, and then delivers the non-underscored event to
+ that same set of boxes in reverse order. So the event travels down
+ the tree to the target, and then back up to the root. The following
+ example prints out "first second third fourth" in that order.
+
+ <pre>
+ <ui:box>
+ _Press1 ++= function(b) { ibex.log.info("first"); }
+ Press1 ++= function(b) { ibex.log.info("fourth"); }
+ <ui:box>
+ _Press1 ++= function(b) { ibex.log.info("second"); }
+ Press1 ++= function(b) { ibex.log.info("third"); }
+ </ui:box>
+ </ui:box>
+ </pre>
+
+ In general, you should use the **non-underscore** names to respond
+ to user input and use the underscored names when you want to override
+ child boxes' behavior or route events to particular boxes (for
+ example, when implementing a focus protocol). This is why the
+ underscored elements are delivered to parents before children (so
+ parents can override their childrens' behavior), but non-underscored
+ events are delivered to children before parents (since, visually, a
+ mouse click is usually "intended" for the leaf box underneath the
+ cursor).
+
+ <heading title="Stopping the Process"/>
+
+ At any point in this sequence, a trap handler can choose not to
+ cascade (by returning [[true]] from the trap handler function).
+ This will immediately cease the propagation of the event. This is how
+ you would indicate that an event has been "handled".
+
+ <heading title="Non-Propagating Events"/>
+
+ Ibex uses the following events to notify a box about changes that
+ only matter to that particular box. These events do not propagate
+ either up or down the tree.
+
+ <property name="Enter Leave">
+ The value [[true]] is written to this property when the mouse (enters/leaves) the box.
+ </property>
+
+ <property name="SizeChange">
+ The value [[true]] is put to this property after the size
+ of this box changes.
</property>
+
+ <property name="ChildChange">
+ When a child is added or removed, that child is written to
+ this property. The write is always performed **after** the
+ addition or removal, so these two cases can be distinguished
+ by checking [[indexof(child)]].
+
+ Note that if the parent's redirect target is set to another
+ box, this trap will only be invoked when children are
+ manipulated by reading and writing to the parent. Reads and
+ writes directly to the redirect target will **not** trigger
+ this trap.
+
+ Note also that this traps is still triggered if a box's
+ [[redirect]] target is **null**. This is useful for
+ boxes that need to accept children and then relocate them
+ elsewhere.
+ </property>
+
+ <section title="Listing of Events">
+
+ <property name="Press1 Press2 Press3">
+ Indicates that the use has pressed a mouse button. On
+ platforms with three mouse buttons, the **middle** button
+ is button 3 -- this ensures that applications written to only
+ use two buttons (1 and 2) will work intuitively on three button
+ platforms.
+ </property>
+
+ <property name="Release1 Release2 Release3">
+ Indicates that the use has released a mouse button.
+ </property>
+
+ <property name="Click1 Click2 Click3">
+ Indicates that the user has pressed and released the
+ mouse button without moving the mouse much (exactly how
+ much is platform-dependent).
+ </property>
+
+ <property name="DoubleClick1 DoubleClick2 DoubleClick3">
+ Indicates that the user has clicked the
+ mouse button twice within a short period of time (exactly how long is platform-dependent).
+ </property>
+
+ <property name="Move">
+ Indicates that the mouse has moved while within this box, or that
+ the mouse while outside this box **if a button was pressed while within this box and has not yet been released**
+ </property>
+
+ <property name="KeyPressed KeyReleased">
+
+ A string is written to this property when a key is pressed or
+ released If the key was any other key, a multi-character
+ string describing the key will be put. For simplicity, we use
+ the VK_ constants in the <link
+ url="http://java.sun.com/products/jdk/1.1/docs/api/java.awt.event.KeyEvent.html#VK_0"
+ text=" Java 1.1 API java.awt.event.KeyEvent class"/>. When a
+ key is pressed or released, the string put will be the portion
+ of its VK_ constant after the underscore, all in lower case.
+
+ <list>
+ If the shift key was depressed immediately before the
+ event took place, then the string will be capitalized. Special
+ keynames are also capitalized; shift+home is reported as
+ "[[HOME]]". Symbols are capitalized as they appear on the
+ keyboard; for example, on an American QWERTY keyboard, shift+2
+ is reported as "[[@]]".
+
+ If the alt, meta, or command key was depressed immediately
+ before this key was pressed, then the string will be prefixed
+ with the string "[[A-]]". If the control key was depressed
+ while this key was pressed, then the string will be prefixed
+ with the string "[[C-]]". If both alt and control are
+ depressed, the string is prefixed with "[[C-A-]]".
+
+ Ibex does not distinguish between a key press resulting from
+ the user physically pushing down a key, and a 'key press'
+ resulting from the keyboard's typematic repeat. In the rare
+ case that an application needs to distinguish between these
+ two events, it should watch for KeyReleased messages and
+ maintain an internal key-state vector.
+ </list>
+ </property>
+ </section>
+ <section title="Re-routing events">
+
+ At any point in the Event Context, you can write to the [[mouse]]
+ property on any box. The value written should be an object with two
+ properties, [[x]] and [[y]]. For example:
+
+ <pre>
+ _Press1 ++= function(p) {
+ mouse = { x: 32, y: 77 };
+ }
+ </pre>
+
+ The coordinates specified are relative to the box whose [[mouse]]
+ property is being written to. There is no need to supply the
+ [[inside]] property; it is computed automatically. Writing to
+ the [[mouse]] property causes Ibex to recompute the eventual
+ target box, and also alter the values returned by [[mouse.x]],
+ [[mouse.y]], and [[mouse.inside]] for any **descendants**
+ of the current box. Writing to the [[mouse]] property also
+ automatically prevents the event from returning to the box's parents
+ -- it is equivalent to not cascading on the non-underscored event.
+ This ensures that child boxes cannot trick their parent boxes into
+ thinking that the mouse has moved.
+
+ If you want the event to "skip over" the boxes between the trapee
+ and the target, or if you want to re-route an event to a box which
+ is not a descendant of the current box, simply write the value to
+ the proper key on the target box.
+
+ <pre>
+ <ui:box>
+ _KeyPressed = function(k) { ibex.log.info("first"); }
+ KeyPressed = function(k) { ibex.log.info("sixth"); }
+ $recipient.target = $target;
+ <ui:box id="recipient">
+ _KeyPressed = function(k) {
+ ibex.log.info("second");
+ thisbox.target.KeyPressed = k;
+ // inhibit cascade; keep event from going to $excluded
+ return true;
+ }
+ KeyPressed = function(k) { ibex.log.info("fifth"); }
+ <ui:box id="excluded">
+ _KeyPressed = function(k) {
+ ibex.log.info("this never happens");
+ }
+ </ui:box>
+ </ui:box>
+ <ui:box id="target">
+ _KeyPressed = function(k) { ibex.log.info("third"); }
+ KeyPressed = function(k) { ibex.log.info("fourth"); }
+ </ui:box>
+ </ui:box>
+ </pre>
+
+ </section>
+
+ <section title="Synthesizing Your Own Events">
+
+ You can create "fake events" by simply writing to the [[mouse]]
+ property and then writing a value to one of the underscored properties
+ on a box. This will have exactly the same effect as if the use had
+ actually pressed a key, clicked a button, or moved the mouse -- they
+ are indistinguishable.
</section>
+ </section>
- </section>
+</section>
+<section title="Ibex Base Services">
<!-- ----------------------------------------------------------------------- -->
<section title="Streams">
</section>
-<!-- ----------------------------------------------------------------------- -->
-<section title="Threads">
-
<section title="Contexts">
From the perspective of an application writer, Ibex is strictly
</section>
</section>
-
-<section title="Events">
-
- Every execution of the Event Context begins with an event, which
- consists of a key/value pair, and a mouse position, which consists of
- an x and y coordinate. The possible keys are [[_Press[1-3]]],
- [[_Release[1-3]]], [[_Click[1-3]]], [[_DoubleClick[1-3]]],
- [[_Move]], [[_KeyPressed]], and [[_KeyReleased]].
-
- Here are two example events:
-
- An event is triggered by writing the key to the value on a box. This
- triggers any trap handlers which may be present. Once these handlers
- have executed, Ibex figures out which child of the current box contains
- the mouse (taking into account that some boxes may cover up others)
- and writes the key and value to that box. If none of the box's
- children contain the mouse position, Ibex removes the leading
- underscore from the key name and writes the value to
- **that** property. Once all the traps on that property have
- executed, the value is written to the box's parent.
-
- Intuitively, Ibex delivers the underscored event to every box from the
- root to the target, and then delivers the non-underscored event to
- that same set of boxes in reverse order. So the event travels down
- the tree to the target, and then back up to the root. The following
- example prints out "first second third fourth" in that order.
-
- <pre>
- <ui:box>
- _Press1 ++= function(b) { ibex.log.info("first"); }
- Press1 ++= function(b) { ibex.log.info("fourth"); }
- <ui:box>
- _Press1 ++= function(b) { ibex.log.info("second"); }
- Press1 ++= function(b) { ibex.log.info("third"); }
- </ui:box>
- </ui:box>
- </pre>
-
- In general, you should use the **non-underscore** names to respond
- to user input and use the underscored names when you want to override
- child boxes' behavior or route events to particular boxes (for
- example, when implementing a focus protocol). This is why the
- underscored elements are delivered to parents before children (so
- parents can override their childrens' behavior), but non-underscored
- events are delivered to children before parents (since, visually, a
- mouse click is usually "intended" for the leaf box underneath the
- cursor).
-
- </section>
-
- <heading title="Stopping the Process"/>
-
- At any point in this sequence, a trap handler can choose not to
- cascade (by returning [[true]] from the trap handler function).
- This will immediately cease the propagation of the event. This is how
- you would indicate that an event has been "handled".
-
- <heading title="Non-Propagating Events"/>
-
- Ibex uses the following events to notify a box about changes that
- only matter to that particular box. These events do not propagate
- either up or down the tree.
-
- <property name="Enter Leave">
- The value [[true]] is written to this property when the mouse (enters/leaves) the box.
- </property>
-
- <property name="SizeChange">
- The value [[true]] is put to this property after the size
- of this box changes.
- </property>
-
- <property name="ChildChange">
- When a child is added or removed, that child is written to
- this property. The write is always performed **after** the
- addition or removal, so these two cases can be distinguished
- by checking [[indexof(child)]].
-
- Note that if the parent's redirect target is set to another
- box, this trap will only be invoked when children are
- manipulated by reading and writing to the parent. Reads and
- writes directly to the redirect target will **not** trigger
- this trap.
-
- Note also that this traps is still triggered if a box's
- [[redirect]] target is **null**. This is useful for
- boxes that need to accept children and then relocate them
- elsewhere.
- </property>
-
- <section title="Listing of Events">
-
- <property name="Press1 Press2 Press3">
- Indicates that the use has pressed a mouse button. On
- platforms with three mouse buttons, the **middle** button
- is button 3 -- this ensures that applications written to only
- use two buttons (1 and 2) will work intuitively on three button
- platforms.
- </property>
-
- <property name="Release1 Release2 Release3">
- Indicates that the use has released a mouse button.
- </property>
-
- <property name="Click1 Click2 Click3">
- Indicates that the user has pressed and released the
- mouse button without moving the mouse much (exactly how
- much is platform-dependent).
- </property>
-
- <property name="DoubleClick1 DoubleClick2 DoubleClick3">
- Indicates that the user has clicked the
- mouse button twice within a short period of time (exactly how long is platform-dependent).
- </property>
-
- <property name="Move">
- Indicates that the mouse has moved while within this box, or that
- the mouse while outside this box **if a button was pressed while within this box and has not yet been released**
- </property>
-
- <property name="KeyPressed KeyReleased">
-
- A string is written to this property when a key is pressed or
- released If the key was any other key, a multi-character
- string describing the key will be put. For simplicity, we use
- the VK_ constants in the <link
- url="http://java.sun.com/products/jdk/1.1/docs/api/java.awt.event.KeyEvent.html#VK_0"
- text=" Java 1.1 API java.awt.event.KeyEvent class"/>. When a
- key is pressed or released, the string put will be the portion
- of its VK_ constant after the underscore, all in lower case.
-
- <list>
- If the shift key was depressed immediately before the
- event took place, then the string will be capitalized. Special
- keynames are also capitalized; shift+home is reported as
- "[[HOME]]". Symbols are capitalized as they appear on the
- keyboard; for example, on an American QWERTY keyboard, shift+2
- is reported as "[[@]]".
-
- If the alt, meta, or command key was depressed immediately
- before this key was pressed, then the string will be prefixed
- with the string "[[A-]]". If the control key was depressed
- while this key was pressed, then the string will be prefixed
- with the string "[[C-]]". If both alt and control are
- depressed, the string is prefixed with "[[C-A-]]".
-
- Ibex does not distinguish between a key press resulting from
- the user physically pushing down a key, and a 'key press'
- resulting from the keyboard's typematic repeat. In the rare
- case that an application needs to distinguish between these
- two events, it should watch for KeyReleased messages and
- maintain an internal key-state vector.
- </list>
- </property>
-
- </section>
-
-</section>
-
<!-- ----------------------------------------------------------------------- -->
<section title="Networking">
</section>
-<!-- ----------------------------------------------------------------------- -->
-<section title="Advanced Topics">
-
- <section title="Re-routing events">
-
- At any point in the Event Context, you can write to the [[mouse]]
- property on any box. The value written should be an object with two
- properties, [[x]] and [[y]]. For example:
-
- <pre>
- _Press1 ++= function(p) {
- mouse = { x: 32, y: 77 };
- }
- </pre>
-
- The coordinates specified are relative to the box whose [[mouse]]
- property is being written to. There is no need to supply the
- [[inside]] property; it is computed automatically. Writing to
- the [[mouse]] property causes Ibex to recompute the eventual
- target box, and also alter the values returned by [[mouse.x]],
- [[mouse.y]], and [[mouse.inside]] for any **descendants**
- of the current box. Writing to the [[mouse]] property also
- automatically prevents the event from returning to the box's parents
- -- it is equivalent to not cascading on the non-underscored event.
- This ensures that child boxes cannot trick their parent boxes into
- thinking that the mouse has moved.
-
- If you want the event to "skip over" the boxes between the trapee
- and the target, or if you want to re-route an event to a box which
- is not a descendant of the current box, simply write the value to
- the proper key on the target box.
-
- <pre>
- <ui:box>
- _KeyPressed = function(k) { ibex.log.info("first"); }
- KeyPressed = function(k) { ibex.log.info("sixth"); }
- $recipient.target = $target;
- <ui:box id="recipient">
- _KeyPressed = function(k) {
- ibex.log.info("second");
- thisbox.target.KeyPressed = k;
- // inhibit cascade; keep event from going to $excluded
- return true;
- }
- KeyPressed = function(k) { ibex.log.info("fifth"); }
- <ui:box id="excluded">
- _KeyPressed = function(k) {
- ibex.log.info("this never happens");
- }
- </ui:box>
- </ui:box>
- <ui:box id="target">
- _KeyPressed = function(k) { ibex.log.info("third"); }
- KeyPressed = function(k) { ibex.log.info("fourth"); }
- </ui:box>
- </ui:box>
- </pre>
-
- </section>
-
- <section title="Synthesizing Your Own Events">
-
- You can create "fake events" by simply writing to the [[mouse]]
- property and then writing a value to one of the underscored properties
- on a box. This will have exactly the same effect as if the use had
- actually pressed a key, clicked a button, or moved the mouse -- they
- are indistinguishable.
-
- </section>
<section title="Ibex self-emulation">
new_ibex.load ++= function() { return newLoadFunction; }
ibex.apply(ibex.box, .main, new_ibex);
</pre>
- </section>
+</section>
</section>
<!-- ----------------------------------------------------------------------- -->
Copyright (C) 2004 Adam Megacz, verbatim redistribution permitted.
Ibex is a trademark of Adam Megacz
**
-
+
</ibex-doc>
\ No newline at end of file