Revision: 3608
http://vexi.svn.sourceforge.net/vexi/?rev=3608&view=rev
Author: clrg
Date: 2009-08-18 10:10:29 +0000 (Tue, 18 Aug 2009)
Log Message:
-----------
- Only fire Leave/Enter when necessary during assignToParent
- Fix add/clear not working on redirects
- Throw exceptions when calling child control methods on a box with a null
redirect
- Documentation updates and trivial code changes
Modified Paths:
--------------
trunk/core/org.vexi.core/src/org/vexi/core/Box.jpp
Modified: trunk/core/org.vexi.core/src/org/vexi/core/Box.jpp
===================================================================
--- trunk/core/org.vexi.core/src/org/vexi/core/Box.jpp 2009-08-18 00:56:54 UTC
(rev 3607)
+++ trunk/core/org.vexi.core/src/org/vexi/core/Box.jpp 2009-08-18 10:10:29 UTC
(rev 3608)
@@ -90,12 +90,13 @@
* </dl>
*
* <h4>Placing</h4>
- * <p>The width of a box is assigned width according to the following
rules:</p>
+ * <p>The width of a box is assigned width according to the 3 following rules,
in strict order of priority:</p>
* <ol><li>It's width is never greater than its maxwidth</li>
- * <li>It's width is never less than its contentwidth, with the exception
of #4</li>
- * <li>If a box is shrunk, the will always be set to contentwidth, with
the exception of #4</li>
- * <li>If a box's maxwidth is less than it's contentwidth, the maxwidth is
used</li></ol>
+ * <li>It's width will not be less than its contentwidth</li>
+ * <li>If a box is shrunk, the width be set to contentwidth</li></ol>
*
+ * <p><b>NB:</b> <em>if a box's maxwidth is less than it's contentwidth, the
maxwidth is used</em></p>
+ *
* <p>Boxes are placed in order in the space allocated to them by the parent
box:</p>
* <dl>
* <dt><code>"place"</code> or <code>"layer"</code></dt>
@@ -344,9 +345,9 @@
// FEATURE: use cx2/cy2 format
/** Adds the intersection of (x,y,w,h) and the node's current actual
geometry to the Surface's dirty list */
private final void dirtyInPlace(boolean clean) { if (clean) { dirty();
clear(PLACE_CLEAN); } }
- private final void dirty() { dirty(0, 0, width, height); }
- private final void dirty(int x, int y, int w, int h) {
- for (Box cur = this; cur != null; cur = cur.parent) {
+ private final void dirty() { dirty(this, 0, 0, width, height); }
+ private static final void dirty(Box b, int x, int y, int w, int h) {
+ for (Box cur = b; cur != null; cur = cur.parent) {
if (!cur.test(DISPLAY)) return;
// get around sub-sampling of enlarged textures
if (cur.texture != null && !cur.test(TILE_IMAGE)) {
@@ -886,7 +887,9 @@
buf.drawPicture(texture, cx1, cy1, cx2, cy2, sx1, sy1, sx2,
sy2);
}
}
-
+
+ // REMARK: text.font may still be null at this point so
+ // cannot use text.isEmpty() but instead use text.width
if (text.width != 0) {
int gap_x = width - text.width;
int gap_y = height - text.height;
@@ -1167,7 +1170,6 @@
// REMARK: anything from here on in is a partial interruption relative
// to this box so we can not call propagateLeave() directly upon it
-
int i;
boolean interrupted = false;
@@ -1376,17 +1378,27 @@
switch (args.length) {
case 0:
//#switch(JSU.toString(method))
- case "forcereflow": reflow(); return null;
+ case "forcereflow":
+ reflow();
+ return null;
case "clear":
- for (int i = JSU.toInt(get(SC_numchildren))-1; i>=0; i--)
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+method+"() on a
box with a null redirect");
+ }
+ for (int i = JSU.toInt(get(SC_numchildren))-1; i>=0; i--) {
put(i, null);
+ }
return null;
//#end
break;
case 1:
//#switch(JSU.toString(method))
case "add":
- put(treeSize(), args[0]); return null;
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+method+"() on a
box with a null redirect");
+ }
+ put(getAndTriggerTraps(SC_numchildren), args[0]);
+ return null;
case "distanceto":
try {
return new DistanceTo(this, (Box)args[0]);
@@ -1394,8 +1406,10 @@
throw new JSExn("Cannot call Box."+method+"() with
non-box argument");
}
case "indexof":
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+method+"() on a
box with a null redirect");
+ }
try {
- // FIXME: test for numchildren trap on redirects
Box b = (Box)args[0];
Box p = this;
while (b.parent != p) {
@@ -1431,16 +1445,18 @@
}
boolean isBoxMethod = false;
//#switch(JSU.toString(method))
+ case "add": isBoxMethod = true;
case "clear": isBoxMethod = true;
+ case "distanceto": isBoxMethod = true;
case "forcereflow": isBoxMethod = true;
- case "add": isBoxMethod = true;
- case "distanceto": isBoxMethod = true;
case "indexof": isBoxMethod = true;
case "sendEvent": isBoxMethod = true;
//#end
- if (isBoxMethod)
+ if (isBoxMethod) {
throw new JSExn("Incorrect number of arguments for Box method
"+method+"()");
- else throw new JSExn("Box method not found: "+method+"()");
+ } else {
+ throw new JSExn("Box method not found: "+method+"()");
+ }
}
/** implements reading from box properties in JS */
@@ -1448,7 +1464,7 @@
// integer properties translate to box children
if (JSU.isInt(name)) return get(JSU.toInt(name));
- /*
+ /* FEATURE: paths
case "path":
if (path != null) return JSU.S(path.toString());
String ret = "";
@@ -1464,23 +1480,50 @@
* <p>The vexi box is a fundamental component from which
* user interfaces are composed.</p>
* */
+
/*****************************************************************************************/
+
/*...@section(Rendering) The rendering properties affect what the box
looks like visually.*/
+
+ /* <p>A box will draw itself on-screen filled with the color or
imagespecified by this
+ * property.</p>
+ *
+ * <p>If the value is a stream, Vexi will try to load the stream as an
image with one of
+ * the supported file extensions. The image will then be rendered in
the on-screen area
+ * represented by the box according to it's <code>tile</code>
property. If the image
+ * fails to load, the error will be re-put to the <code>fill</code>
property.</p>
+ *
+ * <p>If the value is a 5-character hex string (#RGB), 7-character hex
string (#RRGGBB),
+ * 9-character hex string (#AARRGGBB), a box's fill color will be set
to that color.</p>
+ *
+ * <p>If the value is one of the <a
href="http://www.color.org/ICC-1A_1999-04.PDF"
+ * target="_top">ICC</a> colors (the same set of color names supported
by SVG), the box's
+ * fill color is set to that color.</p>
+ *
+ * <p>If the value is null, the fill color will be set to clear
(#00000000).</p>
+ *
+ * @initial_value(null)
+ * @type(String<br/>Stream)
+ * */
case "fill": if (texture == null) return
JSU.S(Color.colorToString(fillcolor)); return texture.stream;
+
/* <p>When an object is written to this property, its stream is read
using the
* <a href="http://www.freetype.org/" target="_top">freetype2
library</a>, and the
* resulting font is used to render the box's text.</p>
*
* @type(Stream)
* @initial_value(vexi.ui.font.vera)
- * @nofollow */
+ * @nofollow
+ * */
case "font": return text.font.stream;
+
/* <p>The size (in points) to render the text.</p>
*
* @type(Number)
* @initial_value(10)
* */
case "fontsize": return Text.sizeToJS(text.pointsize);
+
/*
* The text of a box. Visually null renders the same as the text to ""
(i.e as nothing).
*
@@ -1488,7 +1531,8 @@
* @type(String)
* @nofollow
* */
- case "text": return text.str;
+ case "text": return text.str;
+
/* <p>If the value is a 5-character hex string (#RGB), 7-character hex
string (#RRGGBB),
* 9-character hex string (#AARRGGBB), a box's text color will be set
to that color.</p>
*
@@ -1502,6 +1546,7 @@
* @type(String)
* */
case "textcolor": return JSU.S(Color.colorToString(text.color));
+
/* <p>This property can be set to any of the values specified for
textcolor. If the value
* written is a stream then it will interpreted as a PNG, GIF, or JPEG
image, which will
* become the texture for the box. The box's minwidth and minheight
properties will be
@@ -1553,12 +1598,14 @@
* @initial_value("pack")
* */
case "layout": return test(PACK) ? SC_pack : (test(CLIP) ? SC_place :
SC_layer);
- /* The number of children a box has.
+
+ /* <p><em>Read only</em> reflecting the number of children a box
has.</p>
*
* @initial_value(varies,code=false)
* @type(Number)
* */
case "numchildren": return redirect == null ? NC_0 : redirect == this
? JSU.N(treeSize()) : redirect.getAndTriggerTraps(SC_numchildren);
+
/* <p>The direction the children are layed out in the box when
<code>layout="pack"</code>.
* Valid values are <code>"horizontal"</code> or
<code>"vertical"</code>.</p>
*
@@ -1566,13 +1613,21 @@
* @initial_value("horizontal")
* */
case "orient": return test(ORIENT) ? SC_horizontal : SC_vertical;
- /* <p>Writing to this property sets a box's redirect target. This
property cannot be read
- * from, and can only be written to once.</p>
+
+ /* <p>Writing to this property sets a box's redirect target. Reading
from this property
+ * will return a boolean instead of the redirect target -
<code>true</code> if redirect
+ * target is a box, <code>false</code> if it is <code>null</code>.</p>
*
+ * <p>A box's redirect target must be a descendent of the box. An
error will be thrown
+ * if it is not.</p>
+ *
* @initial_value(thisbox)
* @type(Box)
* */
- case "redirect": return redirect == null ? null : redirect == this ?
JSU.T : redirect.getAndTriggerTraps(SC_redirect);
+ case "redirect":
+ return redirect == null ? null :
+ redirect == this ? JSU.T :
redirect.getAndTriggerTraps(SC_redirect);
+
/* <p>Add a new child to the end of the box's children It is the
equivalent of the
* following VexiScript:</p>
* <pre>box[box.numchildren] = child;</pre>
@@ -1581,15 +1636,25 @@
* @param(b)
* @return(null)
* */
- case "add": return METHOD;
- /* <p>Clears a box of its children:</p>
+ case "add":
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+JSU.toString(name)+"() on
a box with a null redirect");
+ }
+ return redirect == this ? METHOD :
redirect.getAndTriggerTraps(SC_add);
+
+ /* <p>Clear a box of its children:</p>
* <pre>while (box.numchildren) box[0] = null;</pre>
*
* @method
* @param()
* @return(null)
* */
- case "clear": return METHOD;
+ case "clear":
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+JSU.toString(name)+"() on
a box with a null redirect");
+ }
+ return redirect == this ? METHOD :
redirect.getAndTriggerTraps(SC_clear);
+
/* <p>Returns the index of childbox within a box. If childbox is not
an immediate child of
* the box, or an immediate child of the box's redirect, then the
function returns -1.</p>
*
@@ -1597,7 +1662,12 @@
* @param(b)
* @return(Number)
* */
- case "indexof": return redirect == this ? METHOD :
redirect.getAndTriggerTraps(SC_indexof);
+ case "indexof":
+ if (redirect==null) {
+ throw new JSExn("Can not call Box."+JSU.toString(name)+"() on
a box with a null redirect");
+ }
+ return redirect == this ? METHOD :
redirect.getAndTriggerTraps(SC_indexof);
+
/* <p>The Children property is a <em>meta-property</em> representing
a gateway for
* accessing the children of a box.</p>
*
@@ -1632,6 +1702,7 @@
/*****************************************************************************************/
/*...@section(Layout)*/
+
/* <p>If set to true this box will shrink to the smallest size allowed
by its packed
* children and <span>minwidth</span> and <span>minheight</span>
properties.</p>
*
@@ -1646,21 +1717,18 @@
*
* */
case "shrink": return JSU.B(test(HSHRINK) || test(VSHRINK));
- /* <p>Affects how a box is shrunk in the horizontal dimension only. A
horizontally shrunk
- * box will decline any horizontal slack available to it within a
parent box if the parent
- * box has a packed layout strategy and a horizontal orient.</p>
+
+ /* <p>Affects how a box is shrunk in the horizontal and vertical
dimensions.</p>
*
+ * <p>A <em>horizontally</em> shrunk (<code>hshrink</code) box will
decline any horizontal
+ * slack available to it within a parent box, and a
<em>vertically</em> shrunk
+ * (<code>vshrink</code) box will decline vertical slack.</p>
+ *
+ * @group(vshrink)
* @type(Boolean)
* @initial_value(false)
* */
case "hshrink": return JSU.B(test(HSHRINK));
- /* <p>Affects how a box is shrunk in the vertical dimension only. A
vertically shrunk box
- * will decline any vertical slack available to it within a parent box
if the parent box
- * has a packed layout strategy and a vertical orient.</p>
- *
- * @type(Boolean)
- * @initial_value(false)
- * */
case "vshrink": return JSU.B(test(VSHRINK));
/* <p>If a box is a surface, this is the (x, y) coordinates of the
surface.</p>
@@ -1712,6 +1780,19 @@
case "maxwidth": return JSU.N(maxwidth);
case "maxheight": return JSU.N(maxheight);
+ /* <p><em>Read only</em> property describing the <em>minimum</em> size
a box may be in
+ * pixels when constrained by its contents and dimension restricting
properties.</p>
+ *
+ * <p>That is, <em>considering width</em>, the maximum of a box's
minwidth property and the
+ * constrained size of it's children, and the minimum of this value
and the boxes maxwidth
+ * property.</p>
+ *
+ * <p>See the layout section of Box Model for more details on
constraining.</p>
+ *
+ * @group(contentheight)
+ * @type(Number)
+ * @initial_value(0)
+ * */
case "contentwidth": return JSU.N(contentwidth);
case "contentheight": return JSU.N(contentheight);
@@ -1727,12 +1808,14 @@
* @initial_value("center")
* */
case "align": return alignToJS();
- /* Whether to display a box and it's contents.
+
+ /* <p>Whether to display a box and it's contents.</p>
*
* @type(Boolean)
* @initial_value(true)
* */
case "display": return JSU.B(test(DISPLAY));
+
/* <p><em>Read only</em> property describing the visible status of
this box.</p>
*
* <p>Reads <code>false</code> if an ascendent box has its
<code>display</code> property
@@ -1745,10 +1828,10 @@
case "visible": return JSU.B(test(DISPLAY) && (parent!=null ?
parent.isVisible() : Surface.fromBox(this)!=null));
+
/*****************************************************************************************/
+ /*...@section(Other) Miscellaneous*/
-
/*****************************************************************************************/
- /*...@section(Other) Miscellany*/
- case "__treedepth": return JSU.N(depth(this)); // FIXME: this is for
debugging - move to devl?
+ //case "__treedepth": return JSU.N(depth(this)); // FIXME: this is for
debugging - move to devl?
//case "props": return mirror();
/* <p>The shape that the cursor should take when inside this box.</p>
@@ -1767,28 +1850,57 @@
* @initial_value(null)
* @type(String) */
case "cursor": return test(CURSOR) ? super.get(name) : null;
+
/* @constructor @jpp(Box) */
case "distanceto": return METHOD;
+
+ /* <p><em>Read only</em> function that forces reflow to happen on a
box and it's contents.
+ * Useful because reflow is normally deferred until a box becomes
visible on screen, but
+ * sometimes it is desirable to have reflow occur and boxes learn
their size before this
+ * occurs or if it never happens.</p>
+ *
+ * @method
+ * @param()
+ * @return(null)
+ * */
case "forcereflow": return METHOD;
+
/* @constructor @notmethod @jpp(Box) */
case "mouse": return getSurface() == null ? null : new Mouse();
- case "sendEvent": return METHOD;
- /* <p>If a box has a parent, this property returns parent.surface;
otherwise it returns
+
+ /* <p><em>Read only</em> function that can be used to induce an event
on a box and it's
+ * contents.</p>
+ *
+ * @method
+ * @param(event, x, y)
+ * @return(null)
+ * */
+ case "sendEvent": return METHOD;
+
+ /* <p>This special property is read only - alter it by placing a read
trap. Puts to this
+ * property will have no effect and do not throw an error.</p>
+ *
+ * <p>If a box has a parent, this property returns parent.surface;
otherwise it returns
* null. This property is a simple building block that the widget
library uses to implement
* more complex functionality such as focus control and popups.</p>
*
+ * <p>For more details see Surfaces.</p>
+ *
* @initial_value(null)
* @type(<em>varies</em>)
*/
case "surface": return getSurfaceObject(parent);
- /* Returns a reference of a box to itself. If <code>null</code> is
written to this
- * property, and this box is the root box of a surface, the box will
be detached and the
- * surface destroyed. If this box has a parent, it will be detached
from its parent.
+
+ /* <p>Returns a reference of a box to itself. If <code>null</code> is
written to this
+ * property, and this box has a parent, it will be detached from its
parent. If this box is
+ * the root box of a surface, the box will be detached and the surface
destroyed.</p>
+ *
* @type(Box)*/
case "thisbox": return this;
/*****************************************************************************************/
- /*...@section(Frame)*/
+ /*...@section(Frame)*/
+
// see put() for jsdoc
case "Minimized": if (parent == null && getSurface() != null) return
JSU.B(getSurface().minimized);
case "Maximized": if (parent == null && getSurface() != null) return
JSU.B(getSurface().maximized);
@@ -1855,7 +1967,7 @@
// integer properties translate to box children
if (JSU.isInt(name)) { put(JSU.toInt(name), value); return; }
- /*
+ /* FEATURE: paths
case "path":
path = new Path(JSU.toString(value));
float tx = -1 *
Encode.longToFloat2(path.horizontalBounds(Affine.identity()));
@@ -2372,8 +2484,6 @@
if (newparent != null) {
if (i<0) throw new JSExn("Illegal attempt to set the parent of a
box");
}
- // FIXME: test for Enter (but put where? in place()?)
- propagateLeave();
final boolean wasvisible = isVisible();
final JS oldsurface = getSurfaceObject(oldparent);
final JS newsurface = getSurfaceObject(newparent);
@@ -2388,9 +2498,12 @@
if (newparent != null) {
// invoke null put to Children trap on oldparent
oldparent.put(oldparent.indexNode(this), null, false, false);
+ // FIXME: test for Enter (but put where? in place()?)
+ if (!newparent.test(MOUSEINSIDE)) propagateLeave();
} else {
// newparent==null => null put has already occurred
removeFromParent();
+ propagateLeave();
}
}
// assign new parent
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Vexi-svn mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/vexi-svn