UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

399 lines (329 loc) 11.9 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Fabian Jakobs (fjakobs) ************************************************************************ */ /** * The Canvas is an extended Basic layout. * * It is possible to position a widget relative to the right or bottom edge of * the available space. It further supports stretching between left and right * or top and bottom e.g. <code>left=20</code> and <code>right=20</code> would * keep a margin of 20 pixels to both edges. The Canvas layout has support for * percent dimensions and locations. * * *Features* * * * Pixel dimensions and locations * * Percent dimensions and locations * * Stretching between left+right and top+bottom * * Minimum and maximum dimensions * * Children are automatically shrunk to their minimum dimensions if not enough space is available * * Auto sizing (ignoring percent values) * * Margins (also negative ones) * * *Item Properties* * * <ul> * <li><strong>left</strong> <em>(Integer|String)</em>: The left coordinate in pixel or as a percent string e.g. <code>20</code> or <code>30%</code>.</li> * <li><strong>top</strong> <em>(Integer|String)</em>: The top coordinate in pixel or as a percent string e.g. <code>20</code> or <code>30%</code>.</li> * <li><strong>right</strong> <em>(Integer|String)</em>: The right coordinate in pixel or as a percent string e.g. <code>20</code> or <code>30%</code>.</li> * <li><strong>bottom</strong> <em>(Integer|String)</em>: The bottom coordinate in pixel or as a percent string e.g. <code>20</code> or <code>30%</code>.</li> * <li><strong>edge</strong> <em>(Integer|String)</em>: The coordinate in pixels or as a percent string to be used for all four edges. * <li><strong>width</strong> <em>(String)</em>: A percent width e.g. <code>40%</code>.</li> * <li><strong>height</strong> <em>(String)</em>: A percent height e.g. <code>60%</code>.</li> * </ul> * * *Notes* * * <ul> * <li>Stretching (<code>left</code>-><code>right</code> or <code>top</code>-><code>bottom</code>) * has a higher priority than the preferred dimensions</li> * <li>Stretching has a lower priority than the min/max dimensions.</li> * <li>Percent values have no influence on the size hint of the layout.</li> * </ul> * * *Example* * * Here is a little example of how to use the canvas layout. * * <pre class="javascript"> * var container = new qx.ui.container.Composite(new qx.ui.layout.Canvas()); * * // simple positioning * container.add(new qx.ui.core.Widget(), {top: 10, left: 10}); * * // stretch vertically with 10 pixel distance to the parent's top * // and bottom border * container.add(new qx.ui.core.Widget(), {top: 10, left: 10, bottom: 10}); * * // percent positioning and size * container.add(new qx.ui.core.Widget(), {left: "50%", top: "50%", width: "25%", height: "40%"}); * </pre> * * *External Documentation* * * <a href='http://manual.qooxdoo.org/${qxversion}/pages/layout/canvas.html'> * Extended documentation</a> and links to demos of this layout in the qooxdoo manual. */ qx.Class.define("qx.ui.layout.Canvas", { extend : qx.ui.layout.Abstract, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { /** * If desktop mode is active, the children's minimum sizes are ignored * by the layout calculation. This is necessary to prevent the desktop * from growing if e.g. a window is moved beyond the edge of the desktop */ desktop : { check : "Boolean", init: false } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /* --------------------------------------------------------------------------- LAYOUT INTERFACE --------------------------------------------------------------------------- */ // overridden verifyLayoutProperty : qx.core.Environment.select("qx.debug", { "true" : function(item, name, value) { var layoutProperties = { top : 1, left : 1, bottom : 1, right : 1, width : 1, height : 1, edge : 1 }; this.assert(layoutProperties[name] == 1, "The property '"+name+"' is not supported by the Canvas layout!"); if (name =="width" || name == "height") { this.assertMatch(value, qx.ui.layout.Util.PERCENT_VALUE); } else { if (typeof value === "number") { this.assertInteger(value); } else if (qx.lang.Type.isString(value)) { this.assertMatch(value, qx.ui.layout.Util.PERCENT_VALUE); } else { this.fail( "Bad format of layout property '" + name + "': " + value + ". The value must be either an integer or an percent string." ); } } }, "false" : null }), // overridden renderLayout : function(availWidth, availHeight, padding) { var children = this._getLayoutChildren(); var child, size, props; var left, top, right, bottom, width, height; var marginTop, marginRight, marginBottom, marginLeft; for (var i=0, l=children.length; i<l; i++) { child = children[i]; size = child.getSizeHint(); props = child.getLayoutProperties(); // Cache margins marginTop = child.getMarginTop(); marginRight = child.getMarginRight(); marginBottom = child.getMarginBottom(); marginLeft = child.getMarginLeft(); // ************************************** // Processing location // ************************************** left = props.left != null ? props.left : props.edge; if (qx.lang.Type.isString(left)) { left = Math.round(parseFloat(left) * availWidth / 100); } right = props.right != null ? props.right : props.edge; if (qx.lang.Type.isString(right)) { right = Math.round(parseFloat(right) * availWidth / 100); } top = props.top != null ? props.top : props.edge; if (qx.lang.Type.isString(top)) { top = Math.round(parseFloat(top) * availHeight / 100); } bottom = props.bottom != null ? props.bottom : props.edge; if (qx.lang.Type.isString(bottom)) { bottom = Math.round(parseFloat(bottom) * availHeight / 100); } // ************************************** // Processing dimension // ************************************** // Stretching has higher priority than dimension data if (left != null && right != null) { width = availWidth - left - right - marginLeft - marginRight; // Limit computed value if (width < size.minWidth) { width = size.minWidth; } else if (width > size.maxWidth) { width = size.maxWidth; } // Add margin left += marginLeft; } else { // Layout data has higher priority than data from size hint width = props.width; if (width == null) { width = size.width; } else { width = Math.round(parseFloat(width) * availWidth / 100); // Limit computed value if (width < size.minWidth) { width = size.minWidth; } else if (width > size.maxWidth) { width = size.maxWidth; } } if (right != null) { left = availWidth - width - right - marginRight - marginLeft; } else if (left == null) { left = marginLeft; } else { left += marginLeft; } } // Stretching has higher priority than dimension data if (top != null && bottom != null) { height = availHeight - top - bottom - marginTop - marginBottom; // Limit computed value if (height < size.minHeight) { height = size.minHeight; } else if (height > size.maxHeight) { height = size.maxHeight; } // Add margin top += marginTop; } else { // Layout data has higher priority than data from size hint height = props.height; if (height == null) { height = size.height; } else { height = Math.round(parseFloat(height) * availHeight / 100); // Limit computed value if (height < size.minHeight) { height = size.minHeight; } else if (height > size.maxHeight) { height = size.maxHeight; } } if (bottom != null) { top = availHeight - height - bottom - marginBottom - marginTop; } else if (top == null) { top = marginTop; } else { top += marginTop; } } left += padding.left; top += padding.top; // Apply layout child.renderLayout(left, top, width, height); } }, // overridden _computeSizeHint : function() { var neededWidth=0, neededMinWidth=0; var neededHeight=0, neededMinHeight=0; var width, minWidth; var height, minHeight; var children = this._getLayoutChildren(); var child, props, hint; var desktop = this.isDesktop(); var left, top, right, bottom; for (var i=0,l=children.length; i<l; i++) { child = children[i]; props = child.getLayoutProperties(); hint = child.getSizeHint(); // Cache margins var marginX = child.getMarginLeft() + child.getMarginRight(); var marginY = child.getMarginTop() + child.getMarginBottom(); // Compute width width = hint.width+marginX; minWidth = hint.minWidth+marginX; left = props.left != null ? props.left : props.edge; if (left && typeof left === "number") { width += left; minWidth += left; } right = props.right != null ? props.right : props.edge; if (right && typeof right === "number") { width += right; minWidth += right; } neededWidth = Math.max(neededWidth, width); neededMinWidth = desktop ? 0 : Math.max(neededMinWidth, minWidth); // Compute height height = hint.height+marginY; minHeight = hint.minHeight+marginY; top = props.top != null ? props.top : props.edge; if (top && typeof top === "number") { height += top; minHeight += top; } bottom = props.bottom != null ? props.bottom : props.edge; if (bottom && typeof bottom === "number") { height += bottom; minHeight += bottom; } neededHeight = Math.max(neededHeight, height); neededMinHeight = desktop ? 0 : Math.max(neededMinHeight, minHeight); } return { width : neededWidth, minWidth : neededMinWidth, height : neededHeight, minHeight : neededMinHeight }; } } });