GridLayout.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. * GridLayout.js
  3. *
  4. * Copyright, Moxiecode Systems AB
  5. * Released under LGPL License.
  6. *
  7. * License: http://www.tinymce.com/license
  8. * Contributing: http://www.tinymce.com/contributing
  9. */
  10. /**
  11. * This layout manager places controls in a grid.
  12. *
  13. * @setting {Number} spacing Spacing between controls.
  14. * @setting {Number} spacingH Horizontal spacing between controls.
  15. * @setting {Number} spacingV Vertical spacing between controls.
  16. * @setting {Number} columns Number of columns to use.
  17. * @setting {String/Array} alignH start|end|center|stretch or array of values for each column.
  18. * @setting {String/Array} alignV start|end|center|stretch or array of values for each column.
  19. * @setting {String} pack start|end
  20. *
  21. * @class tinymce.ui.GridLayout
  22. * @extends tinymce.ui.AbsoluteLayout
  23. */
  24. define("tinymce/ui/GridLayout", [
  25. "tinymce/ui/AbsoluteLayout"
  26. ], function(AbsoluteLayout) {
  27. "use strict";
  28. return AbsoluteLayout.extend({
  29. /**
  30. * Recalculates the positions of the controls in the specified container.
  31. *
  32. * @method recalc
  33. * @param {tinymce.ui.Container} container Container instance to recalc.
  34. */
  35. recalc: function(container) {
  36. var settings = container.settings, rows, cols, items, contLayoutRect, width, height, rect,
  37. ctrlLayoutRect, ctrl, x, y, posX, posY, ctrlSettings, contPaddingBox, align, spacingH, spacingV, alignH, alignV, maxX, maxY,
  38. colWidths = [], rowHeights = [], ctrlMinWidth, ctrlMinHeight, availableWidth, availableHeight;
  39. // Get layout settings
  40. settings = container.settings;
  41. items = container.items().filter(':visible');
  42. contLayoutRect = container.layoutRect();
  43. cols = settings.columns || Math.ceil(Math.sqrt(items.length));
  44. rows = Math.ceil(items.length / cols);
  45. spacingH = settings.spacingH || settings.spacing || 0;
  46. spacingV = settings.spacingV || settings.spacing || 0;
  47. alignH = settings.alignH || settings.align;
  48. alignV = settings.alignV || settings.align;
  49. contPaddingBox = container._paddingBox;
  50. if (alignH && typeof(alignH) == "string") {
  51. alignH = [alignH];
  52. }
  53. if (alignV && typeof(alignV) == "string") {
  54. alignV = [alignV];
  55. }
  56. // Zero padd columnWidths
  57. for (x = 0; x < cols; x++) {
  58. colWidths.push(0);
  59. }
  60. // Zero padd rowHeights
  61. for (y = 0; y < rows; y++) {
  62. rowHeights.push(0);
  63. }
  64. // Calculate columnWidths and rowHeights
  65. for (y = 0; y < rows; y++) {
  66. for (x = 0; x < cols; x++) {
  67. ctrl = items[y * cols + x];
  68. // Out of bounds
  69. if (!ctrl) {
  70. break;
  71. }
  72. ctrlLayoutRect = ctrl.layoutRect();
  73. ctrlMinWidth = ctrlLayoutRect.minW;
  74. ctrlMinHeight = ctrlLayoutRect.minH;
  75. colWidths[x] = ctrlMinWidth > colWidths[x] ? ctrlMinWidth : colWidths[x];
  76. rowHeights[y] = ctrlMinHeight > rowHeights[y] ? ctrlMinHeight : rowHeights[y];
  77. }
  78. }
  79. // Calculate maxX
  80. availableWidth = contLayoutRect.innerW - contPaddingBox.left - contPaddingBox.right;
  81. for (maxX = 0, x = 0; x < cols; x++) {
  82. maxX += colWidths[x] + (x > 0 ? spacingH : 0);
  83. availableWidth -= (x > 0 ? spacingH : 0) + colWidths[x];
  84. }
  85. // Calculate maxY
  86. availableHeight = contLayoutRect.innerH - contPaddingBox.top - contPaddingBox.bottom;
  87. for (maxY = 0, y = 0; y < rows; y++) {
  88. maxY += rowHeights[y] + (y > 0 ? spacingV : 0);
  89. availableHeight -= (y > 0 ? spacingV : 0) + rowHeights[y];
  90. }
  91. maxX += contPaddingBox.left + contPaddingBox.right;
  92. maxY += contPaddingBox.top + contPaddingBox.bottom;
  93. // Calculate minW/minH
  94. rect = {};
  95. rect.minW = maxX + (contLayoutRect.w - contLayoutRect.innerW);
  96. rect.minH = maxY + (contLayoutRect.h - contLayoutRect.innerH);
  97. rect.contentW = rect.minW - contLayoutRect.deltaW;
  98. rect.contentH = rect.minH - contLayoutRect.deltaH;
  99. rect.minW = Math.min(rect.minW, contLayoutRect.maxW);
  100. rect.minH = Math.min(rect.minH, contLayoutRect.maxH);
  101. rect.minW = Math.max(rect.minW, contLayoutRect.startMinWidth);
  102. rect.minH = Math.max(rect.minH, contLayoutRect.startMinHeight);
  103. // Resize container container if minSize was changed
  104. if (contLayoutRect.autoResize && (rect.minW != contLayoutRect.minW || rect.minH != contLayoutRect.minH)) {
  105. rect.w = rect.minW;
  106. rect.h = rect.minH;
  107. container.layoutRect(rect);
  108. this.recalc(container);
  109. // Forced recalc for example if items are hidden/shown
  110. if (container._lastRect === null) {
  111. var parentCtrl = container.parent();
  112. if (parentCtrl) {
  113. parentCtrl._lastRect = null;
  114. parentCtrl.recalc();
  115. }
  116. }
  117. return;
  118. }
  119. // Update contentW/contentH so absEnd moves correctly
  120. if (contLayoutRect.autoResize) {
  121. rect = container.layoutRect(rect);
  122. rect.contentW = rect.minW - contLayoutRect.deltaW;
  123. rect.contentH = rect.minH - contLayoutRect.deltaH;
  124. }
  125. var flexV;
  126. if (settings.packV == 'start') {
  127. flexV = 0;
  128. } else {
  129. flexV = availableHeight > 0 ? Math.floor(availableHeight / rows) : 0;
  130. }
  131. // Calculate totalFlex
  132. var totalFlex = 0;
  133. var flexWidths = settings.flexWidths;
  134. if (flexWidths) {
  135. for (x = 0; x < flexWidths.length; x++) {
  136. totalFlex += flexWidths[x];
  137. }
  138. } else {
  139. totalFlex = cols;
  140. }
  141. // Calculate new column widths based on flex values
  142. var ratio = availableWidth / totalFlex;
  143. for (x = 0; x < cols; x++) {
  144. colWidths[x] += flexWidths ? flexWidths[x] * ratio : ratio;
  145. }
  146. // Move/resize controls
  147. posY = contPaddingBox.top;
  148. for (y = 0; y < rows; y++) {
  149. posX = contPaddingBox.left;
  150. height = rowHeights[y] + flexV;
  151. for (x = 0; x < cols; x++) {
  152. ctrl = items[y * cols + x];
  153. // No more controls to render then break
  154. if (!ctrl) {
  155. break;
  156. }
  157. // Get control settings and calculate x, y
  158. ctrlSettings = ctrl.settings;
  159. ctrlLayoutRect = ctrl.layoutRect();
  160. width = Math.max(colWidths[x], ctrlLayoutRect.startMinWidth);
  161. ctrlLayoutRect.x = posX;
  162. ctrlLayoutRect.y = posY;
  163. // Align control horizontal
  164. align = ctrlSettings.alignH || (alignH ? (alignH[x] || alignH[0]) : null);
  165. if (align == "center") {
  166. ctrlLayoutRect.x = posX + (width / 2) - (ctrlLayoutRect.w / 2);
  167. } else if (align == "right") {
  168. ctrlLayoutRect.x = posX + width - ctrlLayoutRect.w;
  169. } else if (align == "stretch") {
  170. ctrlLayoutRect.w = width;
  171. }
  172. // Align control vertical
  173. align = ctrlSettings.alignV || (alignV ? (alignV[x] || alignV[0]) : null);
  174. if (align == "center") {
  175. ctrlLayoutRect.y = posY + (height / 2) - (ctrlLayoutRect.h / 2);
  176. } else if (align == "bottom") {
  177. ctrlLayoutRect.y = posY + height - ctrlLayoutRect.h;
  178. } else if (align == "stretch") {
  179. ctrlLayoutRect.h = height;
  180. }
  181. ctrl.layoutRect(ctrlLayoutRect);
  182. posX += width + spacingH;
  183. if (ctrl.recalc) {
  184. ctrl.recalc();
  185. }
  186. }
  187. posY += height + spacingV;
  188. }
  189. }
  190. });
  191. });