diff --git a/platform/features/fixed/bundle.js b/platform/features/fixed/bundle.js index 64f08d97ca..559149ff0c 100644 --- a/platform/features/fixed/bundle.js +++ b/platform/features/fixed/bundle.js @@ -177,7 +177,7 @@ define([ "name": "Y1", "cssClass": "l-input-sm", "control" : "numberfield", - "min": 0 + "min": "0" }, { "property": "editX2", @@ -212,6 +212,21 @@ define([ "control": "numberfield", "description": "Resize object width", "min": "1" + }, + { + "method": "setUnits", + "name": "Units", + "control": "menu-button", + "options": [ + { + "name": "px", + "key": "px" + }, + { + "name": "grid", + "key": "grid" + } + ] } ] }, diff --git a/platform/features/layout/res/templates/elements/line.html b/platform/features/layout/res/templates/elements/line.html index f040a8abc6..402a70bd41 100644 --- a/platform/features/layout/res/templates/elements/line.html +++ b/platform/features/layout/res/templates/elements/line.html @@ -19,12 +19,12 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - - + diff --git a/platform/features/layout/src/FixedController.js b/platform/features/layout/src/FixedController.js index 613a146974..de3c5a32f6 100644 --- a/platform/features/layout/src/FixedController.js +++ b/platform/features/layout/src/FixedController.js @@ -75,7 +75,7 @@ define( // Convert from element x/y/width/height to an // appropriate ng-style argument, to position elements. function convertPosition(elementProxy) { - var gridSize = self.gridSize; + var gridSize = elementProxy.getGridSize(); // Multiply position/dimensions by grid size return { left: (gridSize[0] * elementProxy.x()) + 'px', @@ -114,6 +114,7 @@ define( self.gridSize = layoutGrid; self.elementProxies.forEach(function (elementProxy) { + elementProxy.setGridSize(self.gridSize); elementProxy.style = convertPosition(elementProxy); }); } @@ -121,7 +122,7 @@ define( // Decorate an element for display function makeProxyElement(element, index, elements) { var ElementProxy = ElementProxies[element.type], - e = ElementProxy && new ElementProxy(element, index, elements); + e = ElementProxy && new ElementProxy(element, index, elements, self.gridSize); if (e) { // Provide a displayable position (convert from grid to px) @@ -254,7 +255,8 @@ define( color: "", titled: true, width: DEFAULT_DIMENSIONS[0], - height: DEFAULT_DIMENSIONS[1] + height: DEFAULT_DIMENSIONS[1], + useGrid: true }); //Re-initialize objects, and subscribe to new object @@ -518,4 +520,3 @@ define( return FixedController; } ); - diff --git a/platform/features/layout/src/FixedDragHandle.js b/platform/features/layout/src/FixedDragHandle.js index ca3f8f78fd..7ff5fb0576 100644 --- a/platform/features/layout/src/FixedDragHandle.js +++ b/platform/features/layout/src/FixedDragHandle.js @@ -47,9 +47,10 @@ define( * @memberof platform/features/layout.FixedDragHandle# */ FixedDragHandle.prototype.style = function () { + var gridSize = this.elementHandle.getGridSize(); // Adjust from grid to pixel coordinates - var x = this.elementHandle.x() * this.gridSize[0], - y = this.elementHandle.y() * this.gridSize[1]; + var x = this.elementHandle.x() * gridSize[0], + y = this.elementHandle.y() * gridSize[1]; // Convert to a CSS style centered on that point return { @@ -78,13 +79,14 @@ define( * started */ FixedDragHandle.prototype.continueDrag = function (delta) { + var gridSize = this.elementHandle.getGridSize(); if (this.dragging) { // Update x/y positions (snapping to grid) this.elementHandle.x( - this.dragging.x + Math.round(delta[0] / this.gridSize[0]) + this.dragging.x + Math.round(delta[0] / gridSize[0]) ); this.elementHandle.y( - this.dragging.y + Math.round(delta[1] / this.gridSize[1]) + this.dragging.y + Math.round(delta[1] / gridSize[1]) ); // Invoke update callback if (this.update) { diff --git a/platform/features/layout/src/FixedProxy.js b/platform/features/layout/src/FixedProxy.js index 8d2c03f7f2..6e62b26249 100644 --- a/platform/features/layout/src/FixedProxy.js +++ b/platform/features/layout/src/FixedProxy.js @@ -61,6 +61,7 @@ define( element.width = element.width || 1; element.height = element.height || 1; element.type = type; + element.useGrid = true; // Finally, add it to the view's configuration addElementCallback(element); diff --git a/platform/features/layout/src/elements/BoxProxy.js b/platform/features/layout/src/elements/BoxProxy.js index 6d80d8c1f9..a18d8f3fba 100644 --- a/platform/features/layout/src/elements/BoxProxy.js +++ b/platform/features/layout/src/elements/BoxProxy.js @@ -37,10 +37,11 @@ define( * @param element the fixed position element, as stored in its * configuration * @param index the element's index within its array + * @param {number[]} gridSize the current layout grid size in [x,y] from * @param {Array} elements the full array of elements */ - function BoxProxy(element, index, elements) { - var proxy = new ElementProxy(element, index, elements); + function BoxProxy(element, index, elements, gridSize) { + var proxy = new ElementProxy(element, index, elements, gridSize); /** * Get/set this element's fill color. (Omitting the diff --git a/platform/features/layout/src/elements/ElementProxy.js b/platform/features/layout/src/elements/ElementProxy.js index 7d75219adb..94ac7555b6 100644 --- a/platform/features/layout/src/elements/ElementProxy.js +++ b/platform/features/layout/src/elements/ElementProxy.js @@ -32,6 +32,10 @@ define( bottom: Number.NEGATIVE_INFINITY }; + // Mininmum pixel height and width for objects + var MIN_WIDTH = 10; + var MIN_HEIGHT = 10; + // Ensure a value is non-negative (for x/y setters) function clamp(value) { return Math.max(value, 0); @@ -51,17 +55,29 @@ define( * @param element the fixed position element, as stored in its * configuration * @param index the element's index within its array + * @param {number[]} gridSize the current layout grid size in [x,y] from * @param {Array} elements the full array of elements */ - function ElementProxy(element, index, elements) { - this.resizeHandles = [new ResizeHandle(element, 1, 1)]; - + function ElementProxy(element, index, elements, gridSize) { /** * The element as stored in the view configuration. * @memberof platform/features/layout.ElementProxy# */ this.element = element; + /** + * The current grid size of the layout. + * @memberof platform/features/layout.ElementProxy# + */ + this.gridSize = gridSize; + + this.resizeHandles = [new ResizeHandle( + this.element, + this.getMinWidth(), + this.getMinHeight(), + this.getGridSize() + )]; + /** * Get and/or set the x position of this element. * Units are in fixed position grid space. @@ -108,6 +124,7 @@ define( this.index = index; this.elements = elements; + this.useGrid = element.useGrid; } /** @@ -156,6 +173,95 @@ define( return this.resizeHandles; }; + /** + * Set whether this elements's position is determined in terms of grid + * units or pixels. + * @param {string} key Which unit to use, px or grid + */ + ElementProxy.prototype.setUnits = function (key) { + if (key === 'px' && this.element.useGrid === true) { + this.element.useGrid = false; + this.convertCoordsTo('px'); + } else if (key === 'grid' && this.element.useGrid === false) { + this.element.useGrid = true; + this.convertCoordsTo('grid'); + } + }; + + /** + * Convert this element's coordinates and size from pixels to grid units, + * or vice-versa. + * @param {string} unit When called with 'px', converts grid units to + * pixels; when called with 'grid', snaps element + * to grid units + */ + ElementProxy.prototype.convertCoordsTo = function (unit) { + var gridSize = this.gridSize; + var element = this.element; + var minWidth = this.getMinWidth(); + var minHeight = this.getMinHeight(); + if (unit === 'px') { + element.x = element.x * gridSize[0]; + element.y = element.y * gridSize[1]; + element.width = element.width * gridSize[0]; + element.height = element.height * gridSize[1]; + if (element.x2 && element.y2) { + element.x2 = element.x2 * gridSize[0]; + element.y2 = element.y2 * gridSize[1]; + } + } else if (unit === 'grid') { + element.x = Math.round(element.x / gridSize[0]); + element.y = Math.round(element.y / gridSize[1]); + element.width = Math.max(Math.round(element.width / gridSize[0]), minWidth); + element.height = Math.max(Math.round(element.height / gridSize[1]), minHeight); + if (element.x2 && element.y2) { + element.x2 = Math.round(element.x2 / gridSize[0]); + element.y2 = Math.round(element.y2 / gridSize[1]); + } + } + }; + + /** + * Returns which grid size the element is currently using. + * @return {number[]} The current grid size in [x,y] form if the element + * is currently using the grid, [1,1] if it is using + * pixels. + */ + ElementProxy.prototype.getGridSize = function () { + var gridSize; + if (this.element.useGrid) { + gridSize = this.gridSize; + } else { + gridSize = [1,1]; + } + return gridSize; + }; + + /** + * Set the current grid size stored by this element proxy + * @param {number[]} gridSize The current layout grid size in [x,y] form + */ + ElementProxy.prototype.setGridSize = function (gridSize) { + this.gridSize = gridSize; + }; + + /** + * Get the current minimum element width in grid units + * @return {number} The current minimum element width + */ + ElementProxy.prototype.getMinWidth = function () { + return Math.ceil(MIN_WIDTH / this.getGridSize()[0]); + + }; + + /** + * Get the current minimum element height in grid units + * @return {number} The current minimum element height + */ + ElementProxy.prototype.getMinHeight = function () { + return Math.ceil(MIN_HEIGHT / this.getGridSize()[1]); + }; + return ElementProxy; } ); diff --git a/platform/features/layout/src/elements/ImageProxy.js b/platform/features/layout/src/elements/ImageProxy.js index 1ff5b83ee1..0477d7b444 100644 --- a/platform/features/layout/src/elements/ImageProxy.js +++ b/platform/features/layout/src/elements/ImageProxy.js @@ -36,10 +36,11 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @param {number[]} gridSize the current layout grid size in [x,y] from * @augments {platform/features/layout.ElementProxy} */ - function ImageProxy(element, index, elements) { - var proxy = new ElementProxy(element, index, elements); + function ImageProxy(element, index, elements, gridSize) { + var proxy = new ElementProxy(element, index, elements, gridSize); /** * Get and/or set the displayed text of this element. diff --git a/platform/features/layout/src/elements/LineHandle.js b/platform/features/layout/src/elements/LineHandle.js index d51d5b4631..d9c30238e2 100644 --- a/platform/features/layout/src/elements/LineHandle.js +++ b/platform/features/layout/src/elements/LineHandle.js @@ -35,14 +35,16 @@ define( * @param {string} yProperty field which stores x position * @param {string} xOther field which stores x of other end * @param {string} yOther field which stores y of other end + * @param {number[]} gridSize the current layout grid size in [x,y] from * @implements {platform/features/layout.ElementHandle} */ - function LineHandle(element, xProperty, yProperty, xOther, yOther) { + function LineHandle(element, xProperty, yProperty, xOther, yOther, gridSize) { this.element = element; this.xProperty = xProperty; this.yProperty = yProperty; this.xOther = xOther; this.yOther = yOther; + this.gridSize = gridSize; } LineHandle.prototype.x = function (value) { @@ -83,6 +85,10 @@ define( return element[yProperty]; }; + LineHandle.prototype.getGridSize = function () { + return this.gridSize; + }; + return LineHandle; } diff --git a/platform/features/layout/src/elements/LineProxy.js b/platform/features/layout/src/elements/LineProxy.js index e121561061..f1cebfa78b 100644 --- a/platform/features/layout/src/elements/LineProxy.js +++ b/platform/features/layout/src/elements/LineProxy.js @@ -21,8 +21,8 @@ *****************************************************************************/ define( - ['./ElementProxy', './LineHandle','./AccessorMutator'], - function (ElementProxy, LineHandle,AccessorMutator) { + ['./ElementProxy', './LineHandle', './AccessorMutator'], + function (ElementProxy, LineHandle, AccessorMutator) { /** * Selection/diplay proxy for line elements of a fixed position @@ -33,13 +33,14 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @param {number[]} gridSize the current layout grid size in [x,y] from * @augments {platform/features/layout.ElementProxy} */ - function LineProxy(element, index, elements) { - var proxy = new ElementProxy(element, index, elements), + function LineProxy(element, index, elements, gridSize) { + var proxy = new ElementProxy(element, index, elements, gridSize), handles = [ - new LineHandle(element, 'x', 'y', 'x2', 'y2'), - new LineHandle(element, 'x2', 'y2', 'x', 'y') + new LineHandle(element, 'x', 'y', 'x2', 'y2', proxy.getGridSize()), + new LineHandle(element, 'x2', 'y2', 'x', 'y', proxy.getGridSize()) ]; /** diff --git a/platform/features/layout/src/elements/ResizeHandle.js b/platform/features/layout/src/elements/ResizeHandle.js index 7c5d7384db..f2c3526bf1 100644 --- a/platform/features/layout/src/elements/ResizeHandle.js +++ b/platform/features/layout/src/elements/ResizeHandle.js @@ -35,12 +35,14 @@ define( * @memberof platform/features/layout * @constructor */ - function ResizeHandle(element, minWidth, minHeight) { + function ResizeHandle(element, minWidth, minHeight, gridSize) { this.element = element; // Ensure reasonable defaults this.minWidth = minWidth || 0; this.minHeight = minHeight || 0; + + this.gridSize = gridSize; } ResizeHandle.prototype.x = function (value) { @@ -65,6 +67,10 @@ define( return element.y + element.height; }; + ResizeHandle.prototype.getGridSize = function () { + return this.gridSize; + }; + return ResizeHandle; } diff --git a/platform/features/layout/src/elements/TelemetryProxy.js b/platform/features/layout/src/elements/TelemetryProxy.js index 57668cddd8..bff852af9e 100644 --- a/platform/features/layout/src/elements/TelemetryProxy.js +++ b/platform/features/layout/src/elements/TelemetryProxy.js @@ -21,8 +21,8 @@ *****************************************************************************/ define( - ['./TextProxy','./AccessorMutator'], - function (TextProxy,AccessorMutator) { + ['./TextProxy'], + function (TextProxy) { // Method names to expose from this proxy var HIDE = 'hideTitle', SHOW = 'showTitle'; @@ -39,10 +39,11 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @param {number[]} gridSize the current layout grid size in [x,y] form * @augments {platform/features/layout.ElementProxy} */ - function TelemetryProxy(element, index, elements) { - var proxy = new TextProxy(element, index, elements); + function TelemetryProxy(element, index, elements, gridSize) { + var proxy = new TextProxy(element, index, elements, gridSize); // Toggle the visibility of the title function toggle() { diff --git a/platform/features/layout/src/elements/TextProxy.js b/platform/features/layout/src/elements/TextProxy.js index 4d76d9d896..939c88c5ef 100644 --- a/platform/features/layout/src/elements/TextProxy.js +++ b/platform/features/layout/src/elements/TextProxy.js @@ -36,10 +36,11 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @param {number[]} gridSize the current layout grid size in [x,y] from * @augments {platform/features/layout.ElementProxy} */ - function TextProxy(element, index, elements) { - var proxy = new BoxProxy(element, index, elements); + function TextProxy(element, index, elements, gridSize) { + var proxy = new BoxProxy(element, index, elements, gridSize); /** * Get and/or set the text color of this element.