Revision: 4789
http://sourceforge.net/p/vexi/code/4789
Author: clrg
Date: 2015-05-04 16:16:14 +0000 (Mon, 04 May 2015)
Log Message:
-----------
Core margin+padding implementation
Modified Paths:
--------------
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/jpp/org/vexi/core/Box.jpp
Added Paths:
-----------
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/java/org/vexi/core/Insets.java
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/layout/core.t
Added:
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/java/org/vexi/core/Insets.java
===================================================================
---
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/java/org/vexi/core/Insets.java
(rev 0)
+++
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/java/org/vexi/core/Insets.java
2015-05-04 16:16:14 UTC (rev 4789)
@@ -0,0 +1,110 @@
+// Copyright (c) 2015 the Contributors, as shown in the revision logs.
+// Licensed under the GNU General Public License version 2 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.vexi.core;
+
+import org.ibex.js.JS;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSU;
+import org.ibex.js.Constants;
+
+/**
+ * <p>Encapsulates margin/padding state and JS interaction</p>
+ *
+ * <p>TODO: support different metrics i.e. %/pt/em</p>
+ */
+class Insets {
+ // default empty/0 insets
+ final protected static Insets ZERO = new Insets();
+
+ final int top, right, bottom, left;
+
+ Insets() {
+ top = 0; right = 0; bottom = 0; left = 0;
+ }
+ Insets(int i) {
+ top = i; right = i; bottom = i; left = i;
+ }
+ Insets(int t, int r, int b, int l) {
+ top = t; right = r; bottom = b; left = l;
+ }
+
+ final JS toJS() {
+ if (this==ZERO) return Constants.NC_0;
+ if ((top==right)&&(top==bottom)&&(top==left))
+ return JSU.N(top);
+ if (top==bottom && left==right)
+ return JSU.S(top+" "+left);
+ return JSU.S(top+" "+right+" "+bottom+" "+left);
+ }
+ final JS topToJS() { return JSU.N(top); }
+ final JS leftToJS() { return JSU.N(left); }
+ final JS rightToJS() { return JSU.N(right); }
+ final JS bottomToJS() { return JSU.N(bottom); }
+
+ /** creates an Insets instance by parsing the given JS */
+ final static Insets fromJS(JS inset) throws JSExn {
+ try {
+ if (inset == null)
+ return ZERO;
+
+ if (JSU.isString(inset)) {
+ String[] put = inset.toString().split(" ");
+ if (put.length==1) {
+ int i = Integer.parseInt(put[0]);
+ return new Insets(i);
+ } else if (put.length==2) {
+ int v = Integer.parseInt(put[0]);
+ int h = Integer.parseInt(put[1]);
+ return new Insets(v, h, v, h);
+ } else if (put.length==4) {
+ int t = Integer.parseInt(put[0]);
+ int r = Integer.parseInt(put[1]);
+ int b = Integer.parseInt(put[2]);
+ int l = Integer.parseInt(put[3]);
+ return new Insets(t, r, b, l);
+ } else {
+ throw new Exception();
+ }
+ }
+
+ // Integer
+ int i = JSU.toInt(inset);
+ if (i == 0) return ZERO;
+ return new Insets(i);
+
+ } catch(Exception e) {
+ throw new JSExn("Invalid insets value '"+inset+"'");
+ }
+ }
+
+ final private int insetFromJS(JS inset) throws JSExn {
+ try {
+ return (inset == null) ? 0
+ : (JSU.isInt(inset) ? JSU.toInt(inset)
: Integer.parseInt(JSU.toString(inset)));
+ } catch(Exception e) {
+ throw new JSExn("Invalid inset value '"+inset+"'");
+ }
+ }
+
+ /** creates an Insets instance by parsing the given JS for the top
inset */
+ final Insets fromTopJS(JS top) throws JSExn {
+ return new Insets(insetFromJS(top), right, bottom, left);
+ }
+
+ /** creates an Insets instance by parsing the given JS for the left
inset */
+ final Insets fromLeftJS(JS left) throws JSExn {
+ return new Insets(top, right, bottom, insetFromJS(left));
+ }
+
+ /** creates an Insets instance by parsing the given JS for the right
inset */
+ final Insets fromRightJS(JS right) throws JSExn {
+ return new Insets(top, insetFromJS(right), bottom, left);
+ }
+
+ /** creates an Insets instance by parsing the given JS for the bottom
inset */
+ final Insets fromBottomJS(JS bottom) throws JSExn {
+ return new Insets(top, right, insetFromJS(bottom), left);
+ }
+}
Property changes on:
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/java/org/vexi/core/Insets.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified:
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/jpp/org/vexi/core/Box.jpp
===================================================================
---
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/jpp/org/vexi/core/Box.jpp
2015-05-02 16:30:06 UTC (rev 4788)
+++
branches/vexi3_integrated_layout/org.vexi-core.main/src/main/jpp/org/vexi/core/Box.jpp
2015-05-04 16:16:14 UTC (rev 4789)
@@ -78,8 +78,8 @@
* <p>Herein considering the horizontal dimension, the contentwidth of a box
is the maximum of:</p>
* <ol>
* <li>The value of the box's minwidth property</li>
- * <li>The rendered width of the box's textual content</li>
- * <li>The constrained width of the box's children</li>
+ * <li>The rendered width of the box's textual content plus any padding</li>
+ * <li>The constrained width of the box's children any padding</li>
* </ol>
*
* <p>The constrained width of a box's children depends on the layout policy
of the box:</p>
@@ -174,7 +174,7 @@
// postPutTriggerTrapsAndCatchExceptions(_t_, NAME, _e_);\
// } else {\
// CODE;\
- // }
+ // }\
// Trivial Helper Methods (should be inlined)
/////////////////////////////////////////
@@ -217,7 +217,7 @@
final private boolean test(int mask) { return ((flags & mask) == mask); }
- // Required by Surface/Platform
/////////////////////////////////////////
+ // Required by Surface/Platform /////////////////////////////////////////
public final int getIntFillcolor() { return fillcolor; }
public final Surface getSurface() { return Surface.fromBox(getRoot()); }
@@ -269,8 +269,8 @@
private static final int PACK = 0x00001000;
private static final int CLIP = 0x00002000;
- private static final int HAS_WIDTH_SLACK = 0x00004000;
- private static final int HAS_HEIGHT_SLACK = 0x00008000;
+// private static final int HAS_WIDTH_SLACK = 0x00004000;
+// private static final int HAS_HEIGHT_SLACK = 0x00008000;
private static final int ALIGN_TOP = 0x00010000;
private static final int ALIGN_BOTTOM = 0x00020000;
@@ -423,7 +423,14 @@
private int contentwidth = 0; // == min(maxwidth, max(minwidth, textwidth,
sum(child.contentwidth)))
private int contentheight = 0;
+ private Insets margin = Insets.ZERO;
+ private Insets padding = Insets.ZERO;
+
+ // this is a calculated total of the gaps between packed children
+ // TODO: put into a place() loop or another alternative mechanism
+ private int box_spacing = 0;
+
// Instance Methods
/////////////////////////////////////////////////////////////////////
// FIX not right. Really we want the constructor to be showing, and it
does by default
// if it exists, but need to consider the case if a template is not
present (or indeed
@@ -486,8 +493,8 @@
dirty();
// Tiled images affect contentsize
if (test(TILE_IMAGE)) {
- setMinWidth(texture.getWidth(), true);
- setMinHeight(texture.getHeight(), true);
+ setMinWidth(texture.getWidth(), true);
+ setMinHeight(texture.getHeight(), true);
setConstrain();
}
} else if (texture.getLoadFailed()!=null) {
@@ -624,7 +631,17 @@
}
}
+ private final int nominalWidth() { return min(maxwidth, max(contentwidth,
minwidth)); }
+ private final int nominalHeight() { return min(maxheight,
max(contentheight, minheight)); }
+
+ private final int constrainToWidth(int testwidth, Box c) {
+ return max(testwidth, c.nominalWidth() + max(padding.left,
c.margin.left) + max(padding.right, c.margin.right));
+ }
+ private final int constrainToHeight(int testheight, Box c) {
+ return max(testheight, c.nominalHeight() + max(padding.top,
c.margin.top) + max(padding.bottom, c.margin.bottom));
+ }
+
// Reflow/rendering Pipeline //////////////////////////////////////
/** used to invoke reflow on a box and it's children */
@@ -633,8 +650,8 @@
return;
}
constrain();
- int w = test(HSHRINK) ? contentwidth : min(maxwidth, max(contentwidth,
width));
- int h = test(VSHRINK) ? contentheight : min(maxheight,
max(contentheight, height));
+ int w = test(HSHRINK) ? nominalWidth() : min(maxwidth,
max(contentwidth, width));
+ int h = test(VSHRINK) ? nominalHeight() : min(maxheight,
max(contentheight, height));
tryResize(w, h, true);
place(test(PLACE_CLEAN));
}
@@ -661,8 +678,8 @@
private void constrain() {
int i;
if (test(CONSTRAIN_DESCENDENT)) {
- // clear first, because it is possible
- // that reflow may lead to more reflow
+ // clear first, because it is possible
+ // that reflow may lead to more reflow
clear(CONSTRAIN_DESCENDENT);
// reconstrain any children
for (Box c = getChild(i=0); c != null; c = getChild(++i)) {
@@ -676,10 +693,10 @@
// REMARK: must happen after children's sizes known
// otherwise any update is immediately invalidated
if (trap_test(RESIZE_TRAP)) {
- justTriggerTrapsAndCatchExceptions(SC_Resize, JSU.T);
+ justTriggerTrapsAndCatchExceptions(SC_Resize, JSU.T);
}
- // no reconstrain necessary
+ // no re-constrain necessary
if (!test(CONSTRAIN)) {
return;
}
@@ -687,22 +704,28 @@
// establish new content size
int new_contentwidth = 0, new_contentheight = 0;
if (test(PACK)) {
- //#repeat width/height HORIZONTAL/VERTICAL
+ //#repeat width/height HORIZONTAL/VERTICAL Width/Height left/top
right/bottom
if (test(ORIENT) == HORIZONTAL) {
// accumulate child contentwidth
+ int prior_margin = padding.left;
+ box_spacing = 0;
for (Box c = getChild(i=0); c != null; c = getChild(++i)) {
if (!c.test(DISPLAY)) {
continue;
}
- new_contentwidth += c.contentwidth;
+ int spacing = max(prior_margin, c.margin.left);
+ box_spacing += spacing;
+ new_contentwidth += c.nominalWidth() + spacing;
+ prior_margin = c.margin.right;
}
+ new_contentwidth += max(prior_margin, padding.right);
} else {
// maximum child contentwidth
for (Box c = getChild(i=0); c != null; c = getChild(++i)) {
if (!c.test(DISPLAY)) {
continue;
}
- new_contentwidth = max(new_contentwidth, c.contentwidth);
+ new_contentwidth = constrainToWidth(new_contentwidth, c);
}
}
//#end
@@ -712,12 +735,15 @@
if (!c.test(DISPLAY)) {
continue;
}
- new_contentwidth = max(new_contentwidth, c.contentwidth);
- new_contentheight = max(new_contentheight, c.contentheight);
+ new_contentwidth = constrainToWidth(new_contentwidth, c);
+ new_contentheight = constrainToHeight(new_contentheight, c);
}
}
//#repeat width/height WIDTH/HEIGHT
+ if (test(CLIP))
+ new_contentwidth = max(new_contentwidth, textwidth) + padding.left
+ padding.right;
+/*
if (test(CLIP)) {
if (new_contentwidth < maxwidth && new_contentwidth < minwidth) {
set(HAS_WIDTH_SLACK);
@@ -726,7 +752,7 @@
}
} else {
if (new_contentwidth < maxwidth && (new_contentwidth < minwidth ||
new_contentwidth < textwidth ||
- (texture!=null && new_contentwidth <
texture.getWidth()))) {
+ (texture!=null && new_contentwidth < texture.getWidth())))
{
set(HAS_WIDTH_SLACK);
} else {
clear(HAS_WIDTH_SLACK);
@@ -735,6 +761,7 @@
}
new_contentwidth = min(maxwidth, max(minwidth, new_contentwidth));
+*/
// assign contentwidth and mark for place in parent and placing of
children
if (new_contentwidth != contentwidth) {
@@ -746,7 +773,7 @@
} else {
// constrain contentwidth to frame width
if (getSurface()!=null && !test(SHRINK)) {
- new_contentwidth = min(getSurface().pendingWidth,
new_contentwidth);
+ new_contentwidth = min(getSurface().pendingWidth,
new_contentwidth);
}
if (new_contentwidth != contentwidth) {
setPlaceInTree();
@@ -778,26 +805,45 @@
set(PLACE_CLEAN);
}
+ //#repeat HSHRINK/VSHRINK Width/Height getTargetX/getTargetY x/y tx/ty
width/height left/top right/bottom
+ private final int getTargetWidth(final int availableWidth) {
+ return test(HSHRINK) ? nominalWidth()
+ : max(contentwidth, min(maxwidth, availableWidth - x
+ - max(margin.left, parent.padding.left) -
max(margin.right, parent.padding.right)));
+ }
+ private final int getTargetX(final int availableWidth, final int
targetWidth, final boolean left, final boolean right) {
+ if (left) return margin.left;
+ if (right) return availableWidth - targetWidth - margin.right;
+
+ int tx = (availableWidth - targetWidth) / 2;
+ // honour margins
+ if (tx < margin.left) return margin.left;
+ if (availableWidth - tx - targetWidth < margin.right)
+ return availableWidth - margin.bottom;
+ return tx;
+ }
+ //#end
+
private final void placeChildren(boolean clean) {
if (test(PLACE)) {
clear(PLACE);
- // needed for later resize()
- int child_width, child_height, i;
- // place children individually in box space
if (!test(PACK)) {
+ // place children individually in box space
+ int i;
for (Box child = getChild(i=treeSize()-1); child != null;
child = getChild(--i)) {
if (!child.test(DISPLAY)) {
continue;
}
- child_width = child.test(HSHRINK) ? child.contentwidth :
max(child.contentwidth, min(child.maxwidth, width - child.x));
- child_height = child.test(VSHRINK) ? child.contentheight :
max(child.contentheight, min(child.maxheight, height - child.y));
- child.tryResize(child_width, child_height, clean);
+ child.tryResize(child.getTargetWidth(width),
+ child.getTargetHeight(height),
+ clean);
}
- // pack children into available space
} else {
+ // pack children into available space
int child_x = 0, child_y = 0;
+ int child_width, child_height;
boolean top = test(ALIGN_TOP);
boolean left = test(ALIGN_LEFT);
boolean right = test(ALIGN_RIGHT);
@@ -805,18 +851,23 @@
if (test(ORIENT) == HORIZONTAL) {
// horizontal stacking
- if (!test(HAS_WIDTH_SLACK) && 0 >= width-contentwidth) {
- // simple case - no slack, place children next to
eachother
+ if (contentwidth >= width) {
+ // simple case - no slack, place children next to each
other
+ int i = 0;
+ int prior_margin = padding.left;
for (Box child = getChild(i=0); child != null; child =
getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
// height, y
- child_height = child.test(VSHRINK) ?
child.contentheight : min(child.maxheight, height);
- child_y = top ? 0 : (bottom ? height-child_height
: (height-child_height)/2);
+ child_height = child.getTargetHeight(height);
+ child_y = getTargetY(height, child_height, top,
bottom);
// width, x
- child.tryMoveAndResize(child_x, child_y,
child.contentwidth, child_height, clean);
- child_x += child.contentwidth;
+ child_width = child.nominalWidth();
+ child_x += max(prior_margin, child.margin.left);
+ child.tryMoveAndResize(child_x, child_y,
child_width, child_height, clean);
+ child_x += child_width;
+ prior_margin = child.margin.right;
}
} else {
@@ -824,76 +875,76 @@
// our layout lies somewhere between the min and max
size,
// loop over the children attempting to set their
width to
// targetsize and adjust until it meets the parent
width
- float targetsize = (float)width/(float)treeSize();
+ int packingspace = width - box_spacing;
+ float targetsize = (float)(packingspace) /
(float)treeSize();
float totalsize = 0;
- int numactive = 0;
for (int j=0; j<100; j++) {
+ totalsize = 0;
int min_minsize = MAX_DIMENSION;
int max_maxsize = 0;
- int numflexible = 0;
+ int num_active = 0;
int num_minsize = 0;
int num_maxsize = 0;
+ int num_nolimit = 0;
int num_passive = 0;
+ int i = 0;
for (Box child = getChild(i=0); child != null;
child = getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
- numactive++;
- if (child.test(HSHRINK) ||
child.maxwidth==child.contentwidth) {
+ final int child_nomwidth =
child.nominalWidth();
+ num_active++;
+ if (child.test(HSHRINK) ||
child.maxwidth==child_nomwidth) {
num_passive++;
- totalsize += child.contentwidth;
- } else if (child.contentwidth>targetsize) {
- min_minsize = min(min_minsize,
child.contentwidth);
+ totalsize += child_nomwidth;
+ } else if (child_nomwidth>targetsize) {
+ min_minsize = min(min_minsize,
child_nomwidth);
num_minsize++;
- totalsize += (float)child.contentwidth;
+ totalsize += (float)child_nomwidth;
} else if (child.maxwidth<targetsize) {
max_maxsize = max(max_maxsize,
child.maxwidth);
num_maxsize++;
totalsize += (float)child.maxwidth;
} else {
- numflexible++;
+ num_nolimit++;
totalsize += targetsize;
}
}
- if (numactive==0) {
+ if (num_active==0) {
// no active children - nothing to do
return;
}
// test to see if targetsize produces a solution
that rounds
- // to match the width, adjusting appropriatly if
it does not
+ // to match the width, adjusting appropriately if
it does not
int totalsize_int = (int)(totalsize+0.5);
- if (totalsize_int > width) {
- if (numflexible>0) {
- targetsize -=
(totalsize-(float)width)/(float)numflexible;
+ if (totalsize_int > packingspace) {
+ if (num_nolimit>0) {
+ targetsize -=
(totalsize-(float)packingspace)/(float)num_nolimit;
} else {
- if (num_minsize+num_passive==numactive) {
- // no solution required - avaiable
min-sizes over-consume width
+ if (num_minsize+num_passive==num_active) {
+ // no solution required - available
min-sizes over-consume width
targetsize = width;
break;
}
- targetsize = (float)max_maxsize -
(totalsize-(float)width)/(float)num_maxsize;
+ targetsize = (float)max_maxsize -
(totalsize-(float)packingspace)/(float)num_maxsize;
}
- } else if (totalsize_int < width) {
- if (numflexible>0) {
- targetsize +=
((float)width-totalsize)/(float)numflexible;
+ } else if (totalsize_int < packingspace) {
+ if (num_nolimit>0) {
+ targetsize +=
((float)packingspace-totalsize)/(float)num_nolimit;
} else {
- if (num_maxsize+num_passive==numactive) {
- // no solution required - avaiable
max-sizes do not consume width
+ if (num_maxsize+num_passive==num_active) {
+ // no solution required - available
max-sizes do not consume width
targetsize = width;
break;
}
- targetsize = (float)min_minsize +
((float)width-totalsize)/(float)num_minsize;
+ targetsize = (float)min_minsize +
((float)packingspace-totalsize)/(float)num_minsize;
}
} else {
break;
}
- // reset outer variables and try again
- numactive = 0;
- totalsize = 0;
-
// REMARK: this is error / infinite loop prevention
// giving a helpful report if no solution is found
if (j>=99) {
@@ -903,29 +954,34 @@
if (!child.test(DISPLAY)) {
continue;
}
- Log.system.error(this, "Child "+i+":
"+child.contentwidth+", "+child.maxwidth+", "+child.test(HSHRINK));
+ Log.system.error(this, "Child "+i+":
"+child.nominalWidth()+", "+child.maxwidth+", "+child.test(HSHRINK));
}
}
}
// if there is 'slack' (child boxes do not consume
parent width) then
// align determines whether we pack boxes to left,
centre, or right
- int offset_x = (int)(totalsize+0.5)>=width || left ? 0
: (int)(((float)width-totalsize)/(float)(right?1:2));
+ int offset_x = left ? 0 :
(int)(((float)width-totalsize)/(float)(right?1:2));
// we use total (a float) to keep tabs on final layout
totals
// so we do not get stray pixel sized gaps caused by
rounding
totalsize = 0;
- for (Box child = getChild(i=0); child != null; child =
getChild(++i)) {
+ int prior_margin = padding.left;
+ int i = 0;
+ for (Box child = getChild(i); child != null; child =
getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
// height, y
- child_height = child.test(VSHRINK) ?
child.contentheight : min(child.maxheight, height);
- child_y = top ? 0 : (bottom ? height-child_height
: (height-child_height)/2);
+ child_height = child.getTargetHeight(height);
+ child_y = child.getTargetY(height, child_height,
top, bottom);
+
// width, x
+ totalsize += (float)max(prior_margin,
child.margin.left);
child_x = offset_x + (int)(totalsize+0.5);
- if (child.test(HSHRINK) || child.contentwidth >
targetsize) {
- child_width = child.contentwidth;
+ final int child_nomwidth = child.nominalWidth();
+ if (child.test(HSHRINK) || child_nomwidth >
targetsize) {
+ child_width = child_nomwidth;
totalsize += (float)child_width;
} else if (targetsize > child.maxwidth) {
child_width = child.maxwidth;
@@ -936,23 +992,29 @@
totalsize += targetsize;
}
child.tryMoveAndResize(child_x, child_y,
child_width, child_height, clean);
+ prior_margin = child.margin.right;
}
}
} else {
// vertical stacking - mirrors horizontal stacking code
[see for comments]
- if (!test(HAS_HEIGHT_SLACK) && 0 >= height -
contentheight) {
+ if (contentheight >= height) {
// simple case - no slack
+ int i = 0;
+ int prior_margin = padding.top;
for (Box child = getChild(i=0); child != null; child =
getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
// width, x
- child_width = child.test(HSHRINK) ?
child.contentwidth : min(child.maxwidth, width);
- child_x = left ? 0 : (right ? width-child_width :
(width-child_width)/2);
+ child_width = child.getTargetWidth(width);
+ child_x = child.getTargetX(width, child_width,
left, right);
// height, y
- child.tryMoveAndResize(child_x, child_y,
child_width, child.contentheight, clean);
- child_y += child.contentheight;
+ child_height = child.nominalHeight();
+ child_y += max(prior_margin, child.margin.top);
+ child.tryMoveAndResize(child_x, child_y,
child_width, child_height, clean);
+ child_y += child_height;
+ prior_margin = child.margin.bottom;
}
} else {
@@ -960,108 +1022,113 @@
// our layout lies somewhere between the min and max
size,
// loop over the children attempting to set their
width to
// targetsize and adjust until it meets the parent
width
- float targetsize = (float)height/(float)treeSize();
+ int packingspace = height - box_spacing;
+ float targetsize = (float)packingspace /
(float)treeSize();
float totalsize = 0;
- int numactive = 0;
for (int j=0; j<100; j++) {
+ totalsize = 0;
int min_minsize = MAX_DIMENSION;
int max_maxsize = 0;
- int numflexible = 0;
+ int num_active = 0;
int num_minsize = 0;
int num_maxsize = 0;
+ int num_nolimit = 0;
int num_passive = 0;
+ int i = 0;
for (Box child = getChild(i=0); child != null;
child = getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
- numactive++;
- if (child.test(VSHRINK) ||
child.maxheight==child.contentheight) {
+ num_active++;
+ final int child_nomheight =
child.nominalHeight();
+ if (child.test(VSHRINK) ||
child.maxheight==child_nomheight) {
num_passive++;
- totalsize += child.contentheight;
- } else if (child.contentheight>targetsize) {
- min_minsize = min(min_minsize,
child.contentheight);
+ totalsize += child_nomheight;
+ } else if (child_nomheight>targetsize) {
+ min_minsize = min(min_minsize,
child_nomheight);
num_minsize++;
- totalsize += (float)child.contentheight;
+ totalsize += (float)child_nomheight;
} else if (child.maxheight<targetsize) {
max_maxsize = max(max_maxsize,
child.maxheight);
num_maxsize++;
totalsize += (float)child.maxheight;
} else {
- numflexible++;
+ num_nolimit++;
totalsize += targetsize;
}
}
- if (numactive==0) {
+ if (num_active==0) {
// no active children - nothing to do
return;
}
// test to see if targetsize produces a solution
that rounds
- // to match the height, adjusting appropriatly if
it does not
+ // to match the height, adjusting appropriately if
it does not
int totalsize_int = (int)(totalsize+0.5);
- if (totalsize_int > height) {
- if (numflexible>0) {
- targetsize -=
(totalsize-(float)height)/(float)numflexible;
+ if (totalsize_int > packingspace) {
+ if (num_nolimit>0) {
+ targetsize -=
(totalsize-(float)packingspace)/(float)num_nolimit;
} else {
- if (num_minsize+num_passive==numactive) {
- // no solution required - avaiable
min-sizes over-consume height
+ if (num_minsize+num_passive==num_active) {
+ // no solution required - available
min-sizes over-consume height
targetsize = height;
break;
}
- targetsize = (float)max_maxsize -
(totalsize-(float)height)/(float)num_maxsize;
+ targetsize = (float)max_maxsize -
(totalsize-(float)packingspace)/(float)num_maxsize;
}
- } else if (totalsize_int < height) {
- if (numflexible>0) {
- targetsize +=
((float)height-totalsize)/(float)numflexible;
+ } else if (totalsize_int < packingspace) {
+ if (num_nolimit>0) {
+ targetsize +=
((float)packingspace-totalsize)/(float)num_nolimit;
} else {
- if (num_maxsize+num_passive==numactive) {
- // no solution required - avaiable
max-sizes do not consume height
+ if (num_maxsize+num_passive==num_active) {
+ // no solution required - available
max-sizes do not consume height
targetsize = height;
break;
}
- targetsize = (float)min_minsize +
((float)height-totalsize)/(float)num_minsize;
+ targetsize = (float)min_minsize +
((float)packingspace-totalsize)/(float)num_minsize;
}
} else {
break;
}
- // reset outer variables and try again
- numactive = 0;
- totalsize = 0;
-
// REMARK: this is error / infinite loop prevention
// giving a helpful report if no solution is found
if (j>=99) {
- Log.system.error(this, "Core layout failure,
please report:");
- Log.system.error(this, "Parent height:
"+height);
+ Log.system.error(this, "Core layout failure,
please report:");
+ Log.system.error(this, "Parent height:
"+height);
for (Box child = getChild(i=0); child != null;
child = getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
- Log.system.error(this, "Child "+i+":
"+child.contentheight+", "+child.maxheight+", "+child.test(VSHRINK));
+ Log.system.error(this, "Child "+i+":
"+child.nominalHeight()+", "+child.maxheight+", "+child.test(VSHRINK));
}
}
}
// if there is 'slack' (child boxes do not consume
parent width) then
// align determines whether we pack boxes to left,
centre, or right
- int offset_y = (int)(totalsize+0.5)>=height || top ? 0
: (int)(((float)height-totalsize)/(float)(bottom?1:2));
+ int offset_y = top ? 0 :
(int)(((float)height-totalsize)/(float)(bottom?1:2));
// we use total (a float) to keep tabs on final layout
totals
// so we do not get stray pixel sized gaps caused by
rounding
totalsize = 0;
- for (Box child = getChild(i=0); child != null; child =
getChild(++i)) {
+ int prior_margin = padding.top;
+ int i = 0;
+ for (Box child = getChild(i); child != null; child =
getChild(++i)) {
if (!child.test(DISPLAY)) {
continue;
}
// width, x
- child_width = child.test(HSHRINK) ?
child.contentwidth : min(child.maxwidth, width);
- child_x = left ? 0 : (right ? width-child_width :
(width-child_width)/2);
+ child_width = child.getTargetWidth(width);
+ child_x = child.getTargetX(width, child_width,
left, right);
+
// height, y
+ totalsize += (float)max(prior_margin,
child.margin.top);
child_y = offset_y + (int)(totalsize+0.5);
- if (child.test(VSHRINK) || child.contentheight >
targetsize) {
- child_height = child.contentheight;
+ final int child_nomheight = child.nominalHeight();
+ if (child.test(VSHRINK) || child_nomheight >
targetsize) {
+ child_height = child_nomheight;
totalsize += (float)child_height;
} else if (targetsize > child.maxheight) {
child_height = child.maxheight;
@@ -1072,6 +1139,7 @@
totalsize += targetsize;
}
child.tryMoveAndResize(child_x, child_y,
child_width, child_height, clean);
+ prior_margin = child.margin.bottom;
}
}
}
@@ -1209,13 +1277,13 @@
/** fetches a write trap for property 'name' */
private Trap wtrap(JS name) {
- Trap t = getTrap(name);
+ Trap t = getTrap(name);
return t==null?null:t.findWrite();
}
/** fetches a read trap for property 'name' */
private Trap rtrap(JS name) {
- Trap t = getTrap(name);
+ Trap t = getTrap(name);
return t==null?null:t.findRead();
}
@@ -1811,7 +1879,7 @@
try {
//#switch (JSU.toString(key))
case "from": this.from = (Box)value; return;
- case "to": this.to = (Box)value; return;
+ case "to": this.to = (Box)value; return;
//#end
} catch(ClassCastException cce) {
throw new JSExn("Cannot put non-Box to property
'"+JSU.toString(key)+"' on DistanceTo");
@@ -1852,9 +1920,9 @@
return null;
case "discover":
reflow();
- return null;
+ return null;
case "reflow":
- setConstrain();
+ setConstrain();
return null;
case "render":
reflow();
@@ -1955,16 +2023,16 @@
}
/** returns true if there is a redirect to consume the attempted put */
- final private boolean tryRedirect(JS name, JS value) throws JSExn {
- if (redirect == null) {
- throw new JSExn("Attempt to set '"+name+"' on a box
with a null redirect");
- }
- if (redirect != this) {
- redirect.putAndTriggerTraps(name, value);
- return true;
- }
- return false;
- }
+ final private boolean tryRedirect(JS name, JS value) throws JSExn {
+ if (redirect == null) {
+ throw new JSExn("Attempt to set '"+name+"' on a box with a null
redirect");
+ }
+ if (redirect != this) {
+ redirect.putAndTriggerTraps(name, value);
+ return true;
+ }
+ return false;
+ }
/** implements reading from box properties in JS */
@SuppressWarnings("unused")
@@ -2029,9 +2097,9 @@
* @nofollow
* */
case "font":
- if (redirect == null) return null;
- if (redirect == this) return font.stream;
- return redirect.getAndTriggerTraps(SC_font);
+ if (redirect == null) return null;
+ if (redirect == this) return font.stream;
+ return redirect.getAndTriggerTraps(SC_font);
/* <p>The size, either in points or relative size, to render the
text.</p>
*
@@ -2053,9 +2121,9 @@
* @initial_value("medium")
* */
case "fontsize":
- if (redirect == null) return null;
- if (redirect == this) return sizeToJS(fontsize);
- return redirect.getAndTriggerTraps(SC_fontsize);
+ if (redirect == null) return null;
+ if (redirect == this) return sizeToJS(fontsize);
+ return redirect.getAndTriggerTraps(SC_fontsize);
/* <p>The text of a box. Visually <code>null</code> renders the same
as the text to ""
* (i.e as nothing).</p>
@@ -2065,9 +2133,9 @@
* @nofollow
* */
case "text":
- if (redirect == null) return null;
- if (redirect == this) return text;
- return redirect.getAndTriggerTraps(SC_text);
+ if (redirect == null) return null;
+ if (redirect == this) return text;
+ return redirect.getAndTriggerTraps(SC_text);
/* <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>
@@ -2082,9 +2150,9 @@
* @type(String)
* */
case "textcolor":
- if (redirect == null) return null;
- if (redirect == this) return
JSU.S(Color.colorToString(textcolor));
- return redirect.getAndTriggerTraps(SC_textcolor);
+ if (redirect == null) return null;
+ if (redirect == this) return JSU.S(Color.colorToString(textcolor));
+ return redirect.getAndTriggerTraps(SC_textcolor);
/* <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
@@ -2141,9 +2209,9 @@
* @initial_value("center")
* */
case "align":
- if (redirect == null) return null;
- if (redirect == this) return alignToJS();
- return redirect.getAndTriggerTraps(SC_align);
+ if (redirect == null) return null;
+ if (redirect == this) return alignToJS();
+ return redirect.getAndTriggerTraps(SC_align);
/* <p>The layout strategy for a box - how it lays out it's
children.</p>
*
@@ -2166,9 +2234,9 @@
* @initial_value("pack")
* */
case "layout":
- if (redirect == null) return null;
- if (redirect == this) return test(PACK) ? SC_pack : (test(CLIP)
? SC_place : SC_layer);
- return redirect.getAndTriggerTraps(SC_layout);
+ if (redirect == null) return null;
+ if (redirect == this) return test(PACK) ? SC_pack : (test(CLIP) ?
SC_place : SC_layer);
+ return redirect.getAndTriggerTraps(SC_layout);
/* <p><em>Read only</em> reflecting the number of children a box
has.</p>
*
@@ -2193,9 +2261,9 @@
* @initial_value("horizontal")
* */
case "orient":
- if (redirect == null) return null;
- if (redirect == this) return test(ORIENT) ? SC_horizontal :
SC_vertical;
- return redirect.getAndTriggerTraps(SC_orient);
+ if (redirect == null) return null;
+ if (redirect == this) return test(ORIENT) ? SC_horizontal :
SC_vertical;
+ return redirect.getAndTriggerTraps(SC_orient);
/* <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
@@ -2403,6 +2471,17 @@
case "contentwidth": return JSU.N(contentwidth);
case "contentheight": return JSU.N(contentheight);
+ case "margin": return margin.toJS();
+ case "margin-top": return margin.topToJS();
+ case "margin-left": return margin.leftToJS();
+ case "margin-right": return margin.rightToJS();
+ case "margin-bottom": return margin.bottomToJS();
+ case "padding": return padding.toJS();
+ case "padding-top": return padding.topToJS();
+ case "padding-left": return padding.leftToJS();
+ case "padding-right": return padding.rightToJS();
+ case "padding-bottom": return padding.bottomToJS();
+
/* <p>Whether to display a box and it's contents.</p>
*
* <p>If this box is the root box of a window, its display property
will determine whether
@@ -2627,9 +2706,9 @@
@SuppressWarnings("unused")
public void put(JS name, JS value) throws JSExn {
// integer properties translate to box children
- // SHOULD differentiate the methods here. isInt checks anything that
- // could be an int (even integer strings) so probably not what we
- // actually want.
+ // SHOULD differentiate the methods here. isInt checks anything that
+ // could be an int (even integer strings) so probably not what we
+ // actually want.
if (JSU.isInt(name)) {
put(JSU.toInt(name), value);
return;
@@ -2668,7 +2747,7 @@
throw new JSExn("Attempt to put non-null value to the
'thisbox' property");
}
case "font":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
// We do not convert to a fountain straight away as if it is a
Blessing then
// the fountain won't work as it will refer to the file/url
without .ttf. For
// the moment we handle Blessings separately for this reason.
@@ -2679,7 +2758,7 @@
if (test(FONTSTREAM_SET)) {
clear(FONTSTREAM_SET);
if (font.stream == DEFAULT_STREAM)
- return;
+ return;
setFont(DEFAULT_STREAM, fontsize);
}
} else {
@@ -2694,11 +2773,11 @@
dirty();
}
case "fontsize":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
if (value==null) {
clear(FONTSIZE_SET);
if (fontsize != MEDIUM_SIZE)
- return;
+ return;
setFont(font.stream, MEDIUM_SIZE);
} else {
int ps = jsToSize(value);
@@ -2712,29 +2791,29 @@
dirty();
}
case "text":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
JSString s = value == null ? null :
value instanceof JSString ? (JSString)value :
(JSString)JSU.S(JSU.toString(value));
- if (value == null || EMPTY_STRING.equals(s)) {
- if (text == EMPTY_STRING)
- return;
+ if (value == null || EMPTY_STRING.equals(s)) {
+ if (text == EMPTY_STRING)
+ return;
text = EMPTY_STRING;
- } else {
- if (text.equals(s)) {
- return;
- }
- text = s;
- }
+ } else {
+ if (text.equals(s)) {
+ return;
+ }
+ text = s;
+ }
textCalculateDimensions();
setConstrain();
dirty();
case "textcolor":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
try {
if (value==null) {
clear(FONTCOLOR_SET);
if (textcolor == DEFAULT_COLOR)
- return;
+ return;
textcolor = DEFAULT_COLOR;
} else {
int c = Color.stringToColor(JSU.toString(value));
@@ -2751,32 +2830,32 @@
case "shrink":
boolean set_shrink = JSU.toBoolean(value);
if (test(HSHRINK|VSHRINK) == set_shrink) {
- return;
+ return;
}
// fire other relevant traps and set shrink flags
if (test(HSHRINK) != set_shrink) {
if (trap_test(HSHRINK_TRAP)) {
JS ret = justTriggerTraps(SC_hshrink, value);
if (ret!=Interpreter.CASCADE_PREVENTED) {
- setclear(HSHRINK, JSU.toBoolean(ret));
+ setclear(HSHRINK, JSU.toBoolean(ret));
}
} else {
- setclear(HSHRINK, set_shrink);
+ setclear(HSHRINK, set_shrink);
}
}
if (test(VSHRINK) != set_shrink) {
if (trap_test(VSHRINK_TRAP)) {
JS ret = justTriggerTraps(SC_vshrink, value);
if (ret!=Interpreter.CASCADE_PREVENTED) {
- setclear(VSHRINK, JSU.toBoolean(ret));
+ setclear(VSHRINK, JSU.toBoolean(ret));
}
} else {
- setclear(VSHRINK, set_shrink);
+ setclear(VSHRINK, set_shrink);
}
}
setParentPlace();
case "hshrink":
- boolean set_hshrink = JSU.toBoolean(value);
+ boolean set_hshrink = JSU.toBoolean(value);
if (test(HSHRINK) != set_hshrink) {
setParentPlace();
setclear(HSHRINK, set_hshrink);
@@ -2786,7 +2865,7 @@
}
}
case "vshrink":
- boolean set_hshrink = JSU.toBoolean(value);
+ boolean set_hshrink = JSU.toBoolean(value);
if (test(VSHRINK) != JSU.toBoolean(value)) {
setParentPlace();
setclear(VSHRINK, set_hshrink);
@@ -2811,7 +2890,7 @@
// to change visible state if parent.visible == false as
box.visible is
// always be false) or if this box is attached to a surface
WriteTrapChain trapchain = (parent!=null &&
(parent.get(SC_visible) == JSU.T)) || (parent==null && getSurface()!=null)
- ? fireVisibleTraps(set_display) : null;
+ ? fireVisibleTraps(set_display) : null;
if (set_display) {
set(DISPLAY);
requestReflow();
@@ -2853,15 +2932,15 @@
}
case "fill":
if (value == null && texture != null && test(TILE_IMAGE)) {
- // other cases handled by Box.run()
+ // other cases handled by Box.run()
setConstrain();
}
if (value == null) {
- if (text == null && !test(FILLCOLOR_SET))
- return;
+ if (text == null && !test(FILLCOLOR_SET))
+ return;
clear(FILLCOLOR_SET);
fillcolor = DEFAULT_FILLCOLOR;
- texture = null;
+ texture = null;
} else if (JSU.isString(value)) {
// use as a hex colour value
int newfillcolor = Color.stringToColor(JSU.toString(value));
@@ -2884,25 +2963,25 @@
}
dirty();
case "tile":
- boolean tile = JSU.toBoolean(value);
+ boolean tile = JSU.toBoolean(value);
if (test(TILE_IMAGE) != tile) {
- if (tile)
- set(TILE_IMAGE);
- else clear(TILE_IMAGE);
+ if (tile)
+ set(TILE_IMAGE);
+ else clear(TILE_IMAGE);
dirty();
if (texture != null && texture.isLoaded()) {
if (test(TILE_IMAGE)) {
- // this will cause the Box's minimum dimensions
- // to be set to the image dimensions when tiled
+ // this will cause the Box's minimum dimensions
+ // to be set to the image dimensions when tiled
run(null);
}
}
}
case "align":
- if (tryRedirect(name, value)) return;
- setAlign(value);
+ if (tryRedirect(name, value)) return;
+ setAlign(value);
case "layout":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
if (SC_place.equals(value)) {
if (!test(PACK) && test(CLIP)) {
return;
@@ -2931,7 +3010,7 @@
throw new JSExn("Attempt to set Box property 'layout' to
unsupported value '"+JSU.toString(value)+"'");
}
case "orient":
- if (tryRedirect(name, value)) return;
+ if (tryRedirect(name, value)) return;
if (SC_horizontal.equals(value)) {
if (test(ORIENT)) {
return;
@@ -3009,7 +3088,19 @@
dirty();
}
}
+
+ case "margin": margin = Insets.fromJS(value);
setParentConstrain();
+ case "margin-top": margin = margin.fromTopJS(value);
setParentConstrain();
+ case "margin-left": margin = margin.fromLeftJS(value);
setParentConstrain();
+ case "margin-right": margin = margin.fromRightJS(value);
setParentConstrain();
+ case "margin-bottom": margin = margin.fromBottomJS(value);
setParentConstrain();
+ case "padding": if (tryRedirect(name, value)) return; padding =
Insets.fromJS(value); setConstrain();
+ case "padding-top": if (tryRedirect(name, value)) return; padding =
padding.fromTopJS(value); setConstrain();
+ case "padding-left": if (tryRedirect(name, value)) return; padding =
padding.fromLeftJS(value); setConstrain();
+ case "padding-right": if (tryRedirect(name, value)) return; padding =
padding.fromRightJS(value); setConstrain();
+ case "padding-bottom": if (tryRedirect(name, value)) return; padding =
padding.fromBottomJS(value); setConstrain();
+
// return instead of throw an exception because in some corner cases
// a put is required because surface operates using a read trap, thus
// boxes inheriting a 'surface' box may need to initialize themselves
@@ -3196,7 +3287,7 @@
case "maxheight": trap_set(MAXHEIGHT_TRAP);
case "contentwidth": trap_set(CONTENTWIDTH_TRAP);
case "contentheight": trap_set(CONTENTHEIGHT_TRAP);
- case "surface": trap_set(SURFACE_TRAP);
+ case "surface": trap_set(SURFACE_TRAP);
case "visible": trap_set(VISIBLE_TRAP);
case "Children": trap_set(CHILDREN_TRAP);
case "Enter": trap_set(ENTER_TRAP);
@@ -3573,7 +3664,7 @@
Trap rangeTrap = trap_test(CHILDREN_READ_TRAP) ? rtrap(SC_Children) :
null;
JSExn rangeTrapException = null;
- JS value = null;
+ JS value = null;
try {
if (rangeTrap != null) {
value = Main.SCHEDULER.runBeforeGet(rangeTrap, JSU.N(i));
Added:
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/layout/core.t
===================================================================
---
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/layout/core.t
(rev 0)
+++
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/layout/core.t
2015-05-04 16:16:14 UTC (rev 4789)
@@ -0,0 +1,22 @@
+<vexi xmlns:ui="vexi://ui">
+ <ui:Box fill="white">
+ <ui:Box shrink="true" fill="black" margin="10" padding="10">
+ <ui:Box fill="white">
+ <ui:Box fill="red" minwidth="50" minheight="50" margin="10" />
+ <ui:Box fill="blue" minwidth="50" minheight="50" margin="20" />
+ <ui:Box fill="green" minwidth="50" minheight="50" margin="30"
/>
+ </ui:Box>
+ </ui:Box>
+
+ <ui:Box shrink="true" fill="black" margin="10" padding="10"
orient="vertical">
+ <ui:Box fill="white" orient="vertical">
+ <ui:Box fill="red" minwidth="50" minheight="50" margin="30" />
+ <ui:Box fill="blue" minwidth="50" minheight="50" margin="20" />
+ <ui:Box fill="green" minwidth="50" minheight="50" margin="10"
/>
+ </ui:Box>
+ </ui:Box>
+
+ vexi.ui.frame = thisbox;
+
+ </ui:Box>
+</vexi>
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
Vexi-svn mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/vexi-svn