Wow, Chris, this is really cool.
I have now 0.7 code, but very early I will be porting it and I really need flow layout. So very thank for your work! Cheers - Petr 2008/8/24 Chris Banford <[EMAIL PROTECTED]>: > > Flow now respects each Child's alignY setting. :-) > > Not sure if __rebuildCache() would apply or not to Flow. > > I'm going to take a break from trying to put any more functionality into > this, as I'd rather get feedback from the devs on this, as how it could be > improved and/or cleaned up, before I go making it more convoluted. Might > also be cool to get this into the SVN contrib as a next step? > > Here's a simple use case again for anyone who's curious: > ----------------------------------------------------------------- > /* > > ------------------------------------------------------------------------- > Below is your actual application code... > > ------------------------------------------------------------------------- > */ > var container = new qx.ui.container.Composite( new > qx.ui.layout.Flow(0, "center") ); > > var button1 = new qx.ui.form.Button("First Button is long! Overflow > should ¬ > stay centered (and a wee bit of margin too...)", > "custom/test.png"); > button1.setMargin(3); > button1.setAlignY("middle"); > container.add(button1); > ... Add more buttons here to see Flow in action!.. > this.getRoot().add(container, {edge: 0}); > ----------------------------------------------------------------- > > The first parameter to Flow is for eventual Child spacing, but I haven't > implemented that yet. I've also placed the Flow.js file in with the other > qooxdoo ui.layout files... > > Hope this Flow class can be of use someday. Our current YUI-based tools > implement an Image Library, so we'd need to be able to build a 'flowing' > thumbnail container. This Flow would work for that already -- kinda cool > that qooxdoo is so usable that I could get a crude version of such a layout > object working in just a couple of days from scratch. > > > > Its a glorious day here, at the foot of the Matterhorn, and I'm off for a > fantastic, long bike ride through the Swiss alps! ( > http://bergbahnen.zermatt.ch/e/web-cam/ ) > > > Have a great day! > -Chris > > > > Like so until monday we're going to have a FlowLayout 1.0 full :) > > 2008/8/23 Chris Banford <[EMAIL PROTECTED]> >> >> Me again, >> >> I've managed to get a working implementation of a flow layout that now >> handles >> alignX : ["left". "center", "right"] and to boot it respects margins. >> Turned out to be a tricky little bugger. >> >> It also keeps it in grip if the elements are wider than the available >> space. >> >> Need to start to figure out what is up with Gaps and Spacers. >> >> AlignY shouldn't too bad to get working as well. >> >> -Chris >> >> >> > > > /* ************************************************************************ > > qooxdoo - the new era of web development > http://qooxdoo.org > > http://www.dihedrals.com > > Copyright: > 2008 Dihedrals.com > > License: > LGPL: http://www.gnu.org/licenses/lgpl.html > EPL: http://www.eclipse.org/org/documents/epl-v10.php > See the LICENSE file in the project's top-level directory for details. > > Authors: > * Chris Banford [chris at dihedrals dot com] > * Borrowed liberally from Basic.js and HBox.js > > ************************************************************************ */ > > /** > * A basic layout, which supports positioning of child widgets in a > 'flowing' > * manner, starting at the container's top/left position, placing children > left to right > * (like a HBox) until the there's no remaining room for the next child. > When > * out of room on the current line of elements, a new line is started, > cleared > * below the tallest child of the preceeding line -- a bit like using > 'float' > * in CSS, except that a new line wraps all the way back to the left. > * > * *Example* > * > * Here is a little example of how to use the grid layout. > * > * <pre class="javascript"> > * var flow = new qx.ui.layout.Flow("center") // defaults > to "left" > * > * var container = new qx.ui.container.Composite( new qx.ui.layout.Flow( > flow ) ); > * > * var button1 = new qx.ui.form.Button("First Button is long! Overflow > should stay centered (and a wee bit of margin too...)", "custom/test.png"); > * button1.setMargin(3); > * container.add(button1); > * > * var button2 = new qx.ui.form.Button("2. Button", "custom/test.png"); > * container.add(button2); > * > * var button3 = new qx.ui.form.Button("3rd TALL & really, really, really > long Button", "custom/test.png"); > * button3.setHeight(100); // tall button > * container.add(button3); > * > * var button4 = new qx.ui.form.Button("Number 4", "custom/test.png"); > * container.add(button4); > * > * this.getRoot().add(container, {edge: 0}); > * > * </pre> > * > * *External Documentation* > * > */ > > qx.Class.define("qx.ui.layout.Flow", > { > extend : qx.ui.layout.Abstract, > > > /* > ***************************************************************************** > CONSTRUCTOR > ***************************************************************************** > */ > > /** > * @param spacing {Integer?0} The spacing between child widgets [EMAIL > PROTECTED] > #spacing}. > * @param alignX {String?"left"} Horizontal alignment of the whole children > * block [EMAIL PROTECTED] #alignX}. > */ > construct : function(spacing, alignX) > { > this.base(arguments); > > if (spacing) { > this.setSpacing(spacing); > } > > if (alignX) { > this.setAlignX(alignX); > } > }, > > > > /* > ***************************************************************************** > PROPERTIES > ***************************************************************************** > */ > > properties : > { > /** > * Horizontal alignment of the whole children block. The horizontal > * alignment of the child is completely ignored in HBoxes ( > * [EMAIL PROTECTED] qx.ui.core.LayoutItem#alignX}). > */ > alignX : > { > check : [ "left", "center", "right" ], > init : "left", > apply : "_applyLayoutChange" > }, > > > /** > * Vertical alignment of each child. Can be overridden through > * [EMAIL PROTECTED] qx.ui.core.LayoutItem#alignY}. > */ > alignY : > { > check : [ "top", "middle", "bottom", "baseline" ], > init : "top", > apply : "_applyLayoutChange" > }, > > > /** Horizontal spacing between two children */ > spacing : > { > check : "Integer", > init : 0, > apply : "_applyLayoutChange" > } > > > }, > > > > /* > ***************************************************************************** > MEMBERS > ***************************************************************************** > */ > > members : > { > __currLinesTotalChildWidth : 0, > __currLinesTallestChild : 0, > > /* > > --------------------------------------------------------------------------- > LAYOUT INTERFACE > > --------------------------------------------------------------------------- > */ > > // overridden > verifyLayoutProperty : qx.core.Variant.select("qx.debug", > { > "on" : function(item, name, value) > { > this.assert( false, "The property '"+name+"' is not supported > by the flow layout!" ); > }, > > "off" : null > }), > > //------------------------------------------------------------------- > // overridden > renderLayout : function( availWidth, availHeight ) > { > var util = qx.ui.layout.Util; > var children = this._getLayoutChildren(); > var child, size, left, top, childW; > var marginL, marginR, marginT, marginB; > > var linesChildrenIndexes =[]; > var newLineFlag = false; > > var lineLeft = 0, lineTop = 0; > var tallestChildInLine = 0; > > // Compute gaps > var spacing = this.getSpacing(); > //var separator = this.getSeparator(); > //if (separator) { > // var gaps = > util.computeHorizontalSeparatorGaps(children, spacing, separator); > //} else { > //var gaps = util.computeHorizontalGaps(children, spacing, > true); > //} > this.info( " >> Layout spacing: " + spacing ); > > // Flow Render children > //if ( qx.core.Variant.get("qx.debug") == "on" ){ this.info( > "*** Render Start ***" ); } > var lineCounter = 0; > var currChildIndex = 0 > while ( currChildIndex < children.length ) > { > lineCounter++; > tallestChildInLine = 0; > > linesChildrenIndexes = > this._getIndexesOfChildrenOnALine(children, currChildIndex, availWidth); > > /* > // Debug msgs > if ( qx.core.Variant.get("qx.debug") == "on" ){ > if ( linesChildrenIndexes.length > 0 ) { > this.info( "Line #"+ (lineCounter) +" > is "+this.getAlignX()+" aligned and has " + linesChildrenIndexes.length + "x > children" ); > } else { > this.info( "Line #"+ (lineCounter) +" > is "+this.getAlignX()+" aligned and has 1 child" ); > } > } > */ > > > // Alignment X support > var thisLineCurrLeft = 0; > // AlignX -> "left" > if (this.getAlignX() != "left") { > thisLineCurrLeft = availWidth - > this.__currLinesTotalChildWidth; // AlignX -> "right" > if (this.getAlignX() == "center") { > thisLineCurrLeft = > Math.round(thisLineCurrLeft / 2); // AlignX -> "center" > } > // reverse this Line's children, so the Flow > starts from the > // right edge of the container, with the > proper child order (I think) > if (this.getAlignX() == "right") { > linesChildrenIndexes = > linesChildrenIndexes.concat().reverse(); > } > } > > > > // If there are multiple children that have place on > this Line, > // then loop through them and render each one after > calculating > // the correct left starting position due to alignX. > var thisLineNr; > var len = linesChildrenIndexes.length; > for ( var x=0; x<len; x++ ) { > thisLineNr = linesChildrenIndexes[x]; > child = children[thisLineNr]; > //this.info( " >> Render child: " + > child.getLabel() ); > size = child.getSizeHint(); > // Keep track of the tallest child on this > Line. > marginT = child.getMarginTop(); > marginB = child.getMarginBottom(); > if ( (marginT + size.height + marginB) > > tallestChildInLine ) { > tallestChildInLine = (marginT + > size.height + marginB); > } > marginL = child.getMarginLeft(); > marginR = child.getMarginRight(); > > > // Respect vertical alignment - alignY > top = > util.computeVerticalAlignOffset(child.getAlignY()||this.getAlignY(), > (marginT + size.height + marginB), this.__currLinesTallestChild, marginT, > marginB); > > > child.renderLayout( (thisLineCurrLeft + > marginL), (lineTop + top), size.width, size.height); > > thisLineCurrLeft += (marginL + size.width + > marginR); > currChildIndex++; > } > > > > // Single child on Line > // If this line contain's a single element that is > wider than then > // available space, then it still needs to be > rendered to this Line, > // and the line counter increased to the next line > (otherwise any > // element wider than availWidth wouldn't be > shown...) > // AlignX will have special meaning here! Will prob > mean negative left pos... > if ( len < 1 ) { > child = children[currChildIndex]; > //this.info( " >> Render child wider than > window on its own line: " + child.getLabel() ); > size = child.getSizeHint(); > // Only a single child on this line, so its > automatically the tallest. > marginT = child.getMarginTop(); > marginB = child.getMarginBottom(); > tallestChildInLine = (marginT + size.height + > marginB); > marginL = child.getMarginLeft(); > marginR = child.getMarginRight(); > > > // Adjust this single, possibly overflowing > child for alignX. > if ( (marginL + size.width + marginR) > > availWidth ) { > // Child is overflowing. > if (this.getAlignX() == "center") { > var centeredLeft = > Math.round((availWidth - (marginL + size.width + marginR)) / 2) > //this.info( ">> Single > centered overflow: " + centeredLeft ); > thisLineCurrLeft = > centeredLeft; // AlignX -> "center" > } > if (this.getAlignX() == "right") { > var rightLeft = > Math.round(availWidth - (marginL + size.width + marginR)) > //this.info( ">> Single > centered overflow: " + centeredLeft ); > thisLineCurrLeft = rightLeft; > // AlignX -> "right" > } > } > > // alignY -> When a single child is displayed > alone on a line, > // there is no alignY applied, as this > child's hieght is the Line's height. > child.renderLayout( (thisLineCurrLeft + > marginL), (lineTop + marginT), size.width, size.height); > currChildIndex++; > } > > // update the next line's top starting point. > lineTop += tallestChildInLine; > > } > > }, > > > //------------------------------------------------------------------- > // Take a list of children and a starting index and see how > // many of the buggers will fit on a line of availWidth space. > _getIndexesOfChildrenOnALine : function(children, startIndex, > availWidth) > { > var childIndexList = []; > var child, size, childW; > var marginL, marginR, marginT, marginB; > var currLeft = 0; > var tallestChildInLine = 0; > > for ( var i=startIndex, l=children.length; i<l; i++ ) > { > // Add children indexes, until their accumulated > widths > // won't fit on a single line anymore. > child = children[i]; > size = child.getSizeHint(); > marginL = child.getMarginLeft(); > marginR = child.getMarginRight(); > marginT = child.getMarginTop(); > marginB = child.getMarginBottom(); > childW = marginL + size.width + marginR; > if ( currLeft + childW > availWidth ) { > // Don't save this child and return this > lines list of Child index numbers. > break; > } > // Calc Tallest child on line. > if ( (marginT + size.height + marginB) > > tallestChildInLine ) { > tallestChildInLine = (marginT + size.height + > marginB); > } > childIndexList.push(i); > currLeft += childW; > > } > > // keep track of the total width of all this line's children, > so > // renderLayout() can calculate the starting left position of > the first child, > // so that alignX works. > this.__currLinesTotalChildWidth = currLeft; > // Same for alignY > this.__currLinesTallestChild = tallestChildInLine; > > return childIndexList; > }, > > > // overridden > // Don't need hints for a Flow box (I think) > // Sebastian's tip is to return null, but that's yakking, so > returning 0 instead. > _computeSizeHint : function() > { > return { > width : 0, > height : 0 > }; > } > > > > > } > }); > > ------------------------------------------------------------------------- > This SF.Net email is sponsored by the Moblin Your Move Developer's challenge > Build the coolest Linux based applications with Moblin SDK & win great > prizes > Grand prize is a trip for two to an Open Source event anywhere in the world > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > _______________________________________________ > qooxdoo-devel mailing list > qooxdoo-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel > > ------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ qooxdoo-devel mailing list qooxdoo-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel