From: Mike G. <mik...@ca...> - 2015-05-04 19:55:17
|
Will this fix another issue? How to implement 'border collapse' in grids. i.e. is there a way to make a border part of the margin. On Mon, May 4, 2015 at 5:16 PM, <cl...@us...> wrote: > 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... [truncated message content] |