4 * Copyright, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://www.tinymce.com/license
8 * Contributing: http://www.tinymce.com/contributing
12 * This layout manager places controls in a grid.
14 * @setting {Number} spacing Spacing between controls.
15 * @setting {Number} spacingH Horizontal spacing between controls.
16 * @setting {Number} spacingV Vertical spacing between controls.
17 * @setting {Number} columns Number of columns to use.
18 * @setting {String/Array} alignH start|end|center|stretch or array of values for each column.
19 * @setting {String/Array} alignV start|end|center|stretch or array of values for each column.
20 * @setting {String} pack start|end
22 * @class tinymce.ui.GridLayout
23 * @extends tinymce.ui.AbsoluteLayout
25 define("tinymce/ui/GridLayout", [
26 "tinymce/ui/AbsoluteLayout"
27 ], function(AbsoluteLayout) {
30 return AbsoluteLayout.extend({
32 * Recalculates the positions of the controls in the specified container.
35 * @param {tinymce.ui.Container} container Container instance to recalc.
37 recalc: function(container) {
38 var settings = container.settings, rows, cols, items, contLayoutRect, width, height, rect,
39 ctrlLayoutRect, ctrl, x, y, posX, posY, ctrlSettings, contPaddingBox, align, spacingH, spacingV, alignH, alignV, maxX, maxY,
40 colWidths = [], rowHeights = [], ctrlMinWidth, ctrlMinHeight, alignX, alignY, availableWidth, availableHeight;
42 // Get layout settings
43 settings = container.settings;
44 items = container.items().filter(':visible');
45 contLayoutRect = container.layoutRect();
46 cols = settings.columns || Math.ceil(Math.sqrt(items.length));
47 rows = Math.ceil(items.length / cols);
48 spacingH = settings.spacingH || settings.spacing || 0;
49 spacingV = settings.spacingV || settings.spacing || 0;
50 alignH = settings.alignH || settings.align;
51 alignV = settings.alignV || settings.align;
52 contPaddingBox = container._paddingBox;
54 if (alignH && typeof(alignH) == "string") {
58 if (alignV && typeof(alignV) == "string") {
62 // Zero padd columnWidths
63 for (x = 0; x < cols; x++) {
67 // Zero padd rowHeights
68 for (y = 0; y < rows; y++) {
72 // Calculate columnWidths and rowHeights
73 for (y = 0; y < rows; y++) {
74 for (x = 0; x < cols; x++) {
75 ctrl = items[y * cols + x];
82 ctrlLayoutRect = ctrl.layoutRect();
83 ctrlMinWidth = ctrlLayoutRect.minW;
84 ctrlMinHeight = ctrlLayoutRect.minH;
86 colWidths[x] = ctrlMinWidth > colWidths[x] ? ctrlMinWidth : colWidths[x];
87 rowHeights[y] = ctrlMinHeight > rowHeights[y] ? ctrlMinHeight : rowHeights[y];
92 availableWidth = contLayoutRect.innerW - contPaddingBox.left - contPaddingBox.right;
93 for (maxX = 0, x = 0; x < cols; x++) {
94 maxX += colWidths[x] + (x > 0 ? spacingH : 0);
95 availableWidth -= (x > 0 ? spacingH : 0) + colWidths[x];
99 availableHeight = contLayoutRect.innerH - contPaddingBox.top - contPaddingBox.bottom;
100 for (maxY = 0, y = 0; y < rows; y++) {
101 maxY += rowHeights[y] + (y > 0 ? spacingV : 0);
102 availableHeight -= (y > 0 ? spacingV : 0) + rowHeights[y];
105 maxX += contPaddingBox.left + contPaddingBox.right;
106 maxY += contPaddingBox.top + contPaddingBox.bottom;
108 // Calculate minW/minH
110 rect.minW = maxX + (contLayoutRect.w - contLayoutRect.innerW);
111 rect.minH = maxY + (contLayoutRect.h - contLayoutRect.innerH);
113 rect.contentW = rect.minW - contLayoutRect.deltaW;
114 rect.contentH = rect.minH - contLayoutRect.deltaH;
115 rect.minW = Math.min(rect.minW, contLayoutRect.maxW);
116 rect.minH = Math.min(rect.minH, contLayoutRect.maxH);
117 rect.minW = Math.max(rect.minW, contLayoutRect.startMinWidth);
118 rect.minH = Math.max(rect.minH, contLayoutRect.startMinHeight);
120 // Resize container container if minSize was changed
121 if (contLayoutRect.autoResize && (rect.minW != contLayoutRect.minW || rect.minH != contLayoutRect.minH)) {
125 container.layoutRect(rect);
126 this.recalc(container);
128 // Forced recalc for example if items are hidden/shown
129 if (container._lastRect === null) {
130 var parentCtrl = container.parent();
132 parentCtrl._lastRect = null;
140 // Update contentW/contentH so absEnd moves correctly
141 if (contLayoutRect.autoResize) {
142 rect = container.layoutRect(rect);
143 rect.contentW = rect.minW - contLayoutRect.deltaW;
144 rect.contentH = rect.minH - contLayoutRect.deltaH;
149 if (settings.packV == 'start') {
152 flexV = availableHeight > 0 ? Math.floor(availableHeight / rows) : 0;
155 // Calculate totalFlex
157 var flexWidths = settings.flexWidths;
159 for (x = 0; x < flexWidths.length; x++) {
160 totalFlex += flexWidths[x];
166 // Calculate new column widths based on flex values
167 var ratio = availableWidth / totalFlex;
168 for (x = 0; x < cols; x++) {
169 colWidths[x] += flexWidths ? Math.ceil(flexWidths[x] * ratio) : ratio;
172 // Move/resize controls
173 posY = contPaddingBox.top;
174 for (y = 0; y < rows; y++) {
175 posX = contPaddingBox.left;
176 height = rowHeights[y] + flexV;
178 for (x = 0; x < cols; x++) {
179 ctrl = items[y * cols + x];
181 // No more controls to render then break
186 // Get control settings and calculate x, y
187 ctrlSettings = ctrl.settings;
188 ctrlLayoutRect = ctrl.layoutRect();
189 width = colWidths[x];
191 ctrlLayoutRect.x = posX;
192 ctrlLayoutRect.y = posY;
194 // Align control horizontal
195 align = ctrlSettings.alignH || (alignH ? (alignH[x] || alignH[0]) : null);
196 if (align == "center") {
197 ctrlLayoutRect.x = posX + (width / 2) - (ctrlLayoutRect.w / 2);
198 } else if (align == "right") {
199 ctrlLayoutRect.x = posX + width - ctrlLayoutRect.w;
200 } else if (align == "stretch") {
201 ctrlLayoutRect.w = width;
204 // Align control vertical
205 align = ctrlSettings.alignV || (alignV ? (alignV[x] || alignV[0]) : null);
206 if (align == "center") {
207 ctrlLayoutRect.y = posY + (height / 2) - (ctrlLayoutRect.h / 2);
208 } else if (align == "bottom") {
209 ctrlLayoutRect.y = posY + height - ctrlLayoutRect.h;
210 } else if (align == "stretch") {
211 ctrlLayoutRect.h = height;
214 ctrl.layoutRect(ctrlLayoutRect);
216 posX += width + spacingH;
223 posY += height + spacingV;