UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

368 lines (305 loc) 9.55 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) ************************************************************************ */ /** * A atom layout. Used to place an image and label in relation * to each other. Useful to create buttons, list items, etc. * * *Features* * * * Gap between icon and text (using {@link #gap}) * * Vertical and horizontal mode (using {@link #iconPosition}) * * Sorting options to place first child on top/left or bottom/right (using {@link #iconPosition}) * * Automatically middles/centers content to the available space * * Auto-sizing * * Supports more than two children (will be processed the same way like the previous ones) * * *Item Properties* * * None * * *Notes* * * * Does not support margins and alignment of {@link qx.ui.core.LayoutItem}. * * *Alternative Names* * * None */ qx.Class.define("qx.ui.layout.Atom", { extend : qx.ui.layout.Abstract, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { /** The gap between the icon and the text */ gap : { check : "Integer", init : 4, apply : "_applyLayoutChange" }, /** The position of the icon in relation to the text */ iconPosition : { check : ["left", "top", "right", "bottom", "top-left", "bottom-left", "top-right", "bottom-right"], init : "left", apply : "_applyLayoutChange" }, /** * Whether the content should be rendered centrally when to much space * is available. Enabling this property centers in both axis. The behavior * when disabled of the centering depends on the {@link #iconPosition} property. * If the icon position is <code>left</code> or <code>right</code>, the X axis * is not centered, only the Y axis. If the icon position is <code>top</code> * or <code>bottom</code>, the Y axis is not centered. In case of e.g. an * icon position of <code>top-left</code> no axis is centered. */ center : { check : "Boolean", init : false, apply : "_applyLayoutChange" } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /* --------------------------------------------------------------------------- LAYOUT INTERFACE --------------------------------------------------------------------------- */ // overridden verifyLayoutProperty : qx.core.Environment.select("qx.debug", { "true" : function(item, name, value) { this.assert(false, "The property '"+name+"' is not supported by the Atom layout!"); }, "false" : null }), // overridden renderLayout : function(availWidth, availHeight, padding) { var left = padding.left; var top = padding.top; var Util = qx.ui.layout.Util; var iconPosition = this.getIconPosition(); var children = this._getLayoutChildren(); var length = children.length; var width, height; var child, hint; var gap = this.getGap(); var center = this.getCenter(); // reverse ordering var allowedPositions = ["bottom", "right", "top-right", "bottom-right"]; if (allowedPositions.indexOf(iconPosition) != -1) { var start = length-1; var end = -1; var increment = -1; } else { var start = 0; var end = length; var increment = 1; } // vertical if (iconPosition == "top" || iconPosition == "bottom") { if (center) { var allocatedHeight = 0; for (var i=start; i!=end; i+=increment) { height = children[i].getSizeHint().height; if (height > 0) { allocatedHeight += height; if (i != start) { allocatedHeight += gap; } } } top += Math.round((availHeight - allocatedHeight) / 2); } var childTop = top; for (var i=start; i!=end; i+=increment) { child = children[i]; hint = child.getSizeHint(); width = Math.min(hint.maxWidth, Math.max(availWidth, hint.minWidth)); height = hint.height; left = Util.computeHorizontalAlignOffset("center", width, availWidth) + padding.left; child.renderLayout(left, childTop, width, height); // Ignore pseudo invisible elements if (height > 0) { childTop = top + height + gap; } } } // horizontal // in this way it also supports shrinking of the first label else { var remainingWidth = availWidth; var shrinkTarget = null; var count=0; for (var i=start; i!=end; i+=increment) { child = children[i]; width = child.getSizeHint().width; if (width > 0) { if (!shrinkTarget && child instanceof qx.ui.basic.Label) { shrinkTarget = child; } else { remainingWidth -= width; } count++; } } if (count > 1) { var gapSum = (count - 1) * gap; remainingWidth -= gapSum; } if (shrinkTarget) { var hint = shrinkTarget.getSizeHint(); var shrinkTargetWidth = Math.max(hint.minWidth, Math.min(remainingWidth, hint.maxWidth)); remainingWidth -= shrinkTargetWidth; } if (center && remainingWidth > 0) { left += Math.round(remainingWidth / 2); } for (var i=start; i!=end; i+=increment) { child = children[i]; hint = child.getSizeHint(); height = Math.min(hint.maxHeight, Math.max(availHeight, hint.minHeight)); if (child === shrinkTarget) { width = shrinkTargetWidth; } else { width = hint.width; } var align = "middle"; if(iconPosition == "top-left" || iconPosition == "top-right"){ align = "top"; } else if (iconPosition == "bottom-left" || iconPosition == "bottom-right") { align = "bottom"; } var childTop = top + Util.computeVerticalAlignOffset(align, hint.height, availHeight); child.renderLayout(left, childTop, width, height); // Ignore pseudo invisible childs for gap e.g. // empty text or unavailable images if (width > 0) { left += width + gap; } } } }, // overridden _computeSizeHint : function() { var children = this._getLayoutChildren(); var length = children.length; var hint, result; // Fast path for only one child if (length === 1) { var hint = children[0].getSizeHint(); // Work on a copy, but do not respect max // values as a Atom can be rendered bigger // than its content. result = { width : hint.width, height : hint.height, minWidth : hint.minWidth, minHeight : hint.minHeight }; } else { var minWidth=0, width=0; var minHeight=0, height=0; var iconPosition = this.getIconPosition(); var gap = this.getGap(); if (iconPosition === "top" || iconPosition === "bottom") { var count = 0; for (var i=0; i<length; i++) { hint = children[i].getSizeHint(); // Max of widths width = Math.max(width, hint.width); minWidth = Math.max(minWidth, hint.minWidth); // Sum of heights if (hint.height > 0) { height += hint.height; minHeight += hint.minHeight; count++; } } if (count > 1) { var gapSum = (count-1) * gap; height += gapSum; minHeight += gapSum; } } else { var count=0; for (var i=0; i<length; i++) { hint = children[i].getSizeHint(); // Max of heights height = Math.max(height, hint.height); minHeight = Math.max(minHeight, hint.minHeight); // Sum of widths if (hint.width > 0) { width += hint.width; minWidth += hint.minWidth; count++; } } if (count > 1) { var gapSum = (count-1) * gap; width += gapSum; minWidth += gapSum; } } // Build hint result = { minWidth : minWidth, width : width, minHeight : minHeight, height : height }; } return result; } } });