PageRenderTime 25ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/qooxdoo/framework/source/class/qx/ui/layout/Atom.js

https://github.com/stephaneerard/qooxdoo
JavaScript | 364 lines | 219 code | 56 blank | 89 comment | 36 complexity | 11926dda2ce3ab6f999f15fd8cc23243 MD5 | raw file
  1. /* ************************************************************************
  2. qooxdoo - the new era of web development
  3. http://qooxdoo.org
  4. Copyright:
  5. 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
  6. License:
  7. LGPL: http://www.gnu.org/licenses/lgpl.html
  8. EPL: http://www.eclipse.org/org/documents/epl-v10.php
  9. See the LICENSE file in the project's top-level directory for details.
  10. Authors:
  11. * Sebastian Werner (wpbasti)
  12. * Fabian Jakobs (fjakobs)
  13. ************************************************************************ */
  14. /**
  15. * A atom layout. Used to place an image and label in relation
  16. * to each other. Useful to create buttons, list items, etc.
  17. *
  18. * *Features*
  19. *
  20. * * Gap between icon and text (using {@link #gap})
  21. * * Vertical and horizontal mode (using {@link #iconPosition})
  22. * * Sorting options to place first child on top/left or bottom/right (using {@link #iconPosition})
  23. * * Automatically middles/centers content to the available space
  24. * * Auto-sizing
  25. * * Supports more than two children (will be processed the same way like the previous ones)
  26. *
  27. * *Item Properties*
  28. *
  29. * None
  30. *
  31. * *Notes*
  32. *
  33. * * Does not support margins and alignment of {@link qx.ui.core.LayoutItem}.
  34. *
  35. * *External Documentation*
  36. *
  37. * <a href='http://manual.qooxdoo.org/1.2/pages/layout/atom.html'>
  38. * Extended documentation</a> and links to demos of this layout in the qooxdoo wiki.
  39. *
  40. * *Alternative Names*
  41. *
  42. * None
  43. */
  44. qx.Class.define("qx.ui.layout.Atom",
  45. {
  46. extend : qx.ui.layout.Abstract,
  47. /*
  48. *****************************************************************************
  49. PROPERTIES
  50. *****************************************************************************
  51. */
  52. properties :
  53. {
  54. /** The gap between the icon and the text */
  55. gap :
  56. {
  57. check : "Integer",
  58. init : 4,
  59. apply : "_applyLayoutChange"
  60. },
  61. /** The position of the icon in relation to the text */
  62. iconPosition :
  63. {
  64. check : [ "left", "top", "right", "bottom" ],
  65. init : "left",
  66. apply : "_applyLayoutChange"
  67. },
  68. /**
  69. * Whether the content should be rendered centrally when to much space
  70. * is available. Affects both axis.
  71. */
  72. center :
  73. {
  74. check : "Boolean",
  75. init : false,
  76. apply : "_applyLayoutChange"
  77. }
  78. },
  79. /*
  80. *****************************************************************************
  81. MEMBERS
  82. *****************************************************************************
  83. */
  84. members :
  85. {
  86. /*
  87. ---------------------------------------------------------------------------
  88. LAYOUT INTERFACE
  89. ---------------------------------------------------------------------------
  90. */
  91. // overridden
  92. verifyLayoutProperty : qx.core.Variant.select("qx.debug",
  93. {
  94. "on" : function(item, name, value) {
  95. this.assert(false, "The property '"+name+"' is not supported by the Atom layout!");
  96. },
  97. "off" : null
  98. }),
  99. // overridden
  100. renderLayout : function(availWidth, availHeight)
  101. {
  102. var Util = qx.ui.layout.Util;
  103. var iconPosition = this.getIconPosition();
  104. var children = this._getLayoutChildren();
  105. var length = children.length;
  106. var left, top, width, height;
  107. var child, hint;
  108. var gap = this.getGap();
  109. var center = this.getCenter();
  110. // reverse ordering
  111. if (iconPosition === "bottom" || iconPosition === "right")
  112. {
  113. var start = length-1;
  114. var end = -1;
  115. var increment = -1;
  116. }
  117. else
  118. {
  119. var start = 0;
  120. var end = length;
  121. var increment = 1;
  122. }
  123. // vertical
  124. if (iconPosition == "top" || iconPosition == "bottom")
  125. {
  126. if (center)
  127. {
  128. var allocatedHeight = 0;
  129. for (var i=start; i!=end; i+=increment)
  130. {
  131. height = children[i].getSizeHint().height;
  132. if (height > 0)
  133. {
  134. allocatedHeight += height;
  135. if (i != start) {
  136. allocatedHeight += gap;
  137. }
  138. }
  139. }
  140. top = Math.round((availHeight - allocatedHeight) / 2);
  141. }
  142. else
  143. {
  144. top = 0;
  145. }
  146. for (var i=start; i!=end; i+=increment)
  147. {
  148. child = children[i];
  149. hint = child.getSizeHint();
  150. width = Math.min(hint.maxWidth, Math.max(availWidth, hint.minWidth));
  151. height = hint.height;
  152. left = Util.computeHorizontalAlignOffset("center", width, availWidth);
  153. child.renderLayout(left, top, width, height);
  154. // Ignore pseudo invisible elements
  155. if (height > 0) {
  156. top += height + gap;
  157. }
  158. }
  159. }
  160. // horizontal
  161. // in this way it also supports shrinking of the first label
  162. else
  163. {
  164. var remainingWidth = availWidth;
  165. var shrinkTarget = null;
  166. var count=0;
  167. for (var i=start; i!=end; i+=increment)
  168. {
  169. child = children[i];
  170. width = child.getSizeHint().width;
  171. if (width > 0)
  172. {
  173. if (!shrinkTarget && child instanceof qx.ui.basic.Label) {
  174. shrinkTarget = child;
  175. } else {
  176. remainingWidth -= width;
  177. }
  178. count++;
  179. }
  180. }
  181. if (count > 1)
  182. {
  183. var gapSum = (count - 1) * gap;
  184. remainingWidth -= gapSum;
  185. }
  186. if (shrinkTarget)
  187. {
  188. var hint = shrinkTarget.getSizeHint();
  189. var shrinkTargetWidth = Math.max(hint.minWidth, Math.min(remainingWidth, hint.maxWidth));
  190. remainingWidth -= shrinkTargetWidth;
  191. }
  192. if (center && remainingWidth > 0) {
  193. left = Math.round(remainingWidth / 2);
  194. } else {
  195. left = 0;
  196. }
  197. for (var i=start; i!=end; i+=increment)
  198. {
  199. child = children[i];
  200. hint = child.getSizeHint();
  201. height = Math.min(hint.maxHeight, Math.max(availHeight, hint.minHeight));
  202. if (child === shrinkTarget) {
  203. width = shrinkTargetWidth;
  204. } else {
  205. width = hint.width;
  206. }
  207. top = Util.computeVerticalAlignOffset("middle", hint.height, availHeight);
  208. child.renderLayout(left, top, width, height);
  209. // Ignore pseudo invisible childs for gap e.g.
  210. // empty text or unavailable images
  211. if (width > 0) {
  212. left += width + gap;
  213. }
  214. }
  215. }
  216. },
  217. // overridden
  218. _computeSizeHint : function()
  219. {
  220. var children = this._getLayoutChildren();
  221. var length = children.length;
  222. var hint, result;
  223. // Fast path for only one child
  224. if (length === 1)
  225. {
  226. var hint = children[0].getSizeHint();
  227. // Work on a copy, but do not respect max
  228. // values as a Atom can be rendered bigger
  229. // than its content.
  230. result = {
  231. width : hint.width,
  232. height : hint.height,
  233. minWidth : hint.minWidth,
  234. minHeight : hint.minHeight
  235. };
  236. }
  237. else
  238. {
  239. var minWidth=0, width=0;
  240. var minHeight=0, height=0;
  241. var iconPosition = this.getIconPosition();
  242. var gap = this.getGap();
  243. if (iconPosition === "top" || iconPosition === "bottom")
  244. {
  245. var count = 0;
  246. for (var i=0; i<length; i++)
  247. {
  248. hint = children[i].getSizeHint();
  249. // Max of widths
  250. width = Math.max(width, hint.width);
  251. minWidth = Math.max(minWidth, hint.minWidth);
  252. // Sum of heights
  253. if (hint.height > 0)
  254. {
  255. height += hint.height;
  256. minHeight += hint.minHeight;
  257. count++;
  258. }
  259. }
  260. if (count > 1)
  261. {
  262. var gapSum = (count-1) * gap;
  263. height += gapSum;
  264. minHeight += gapSum;
  265. }
  266. }
  267. else
  268. {
  269. var count=0;
  270. for (var i=0; i<length; i++)
  271. {
  272. hint = children[i].getSizeHint();
  273. // Max of heights
  274. height = Math.max(height, hint.height);
  275. minHeight = Math.max(minHeight, hint.minHeight);
  276. // Sum of widths
  277. if (hint.width > 0)
  278. {
  279. width += hint.width;
  280. minWidth += hint.minWidth;
  281. count++;
  282. }
  283. }
  284. if (count > 1)
  285. {
  286. var gapSum = (count-1) * gap;
  287. width += gapSum;
  288. minWidth += gapSum;
  289. }
  290. }
  291. // Build hint
  292. result = {
  293. minWidth : minWidth,
  294. width : width,
  295. minHeight : minHeight,
  296. height : height
  297. };
  298. }
  299. return result;
  300. }
  301. }
  302. });