Index: chrome/browser/resources/options/chromeos/display_layout_manager.js |
diff --git a/chrome/browser/resources/options/chromeos/display_layout_manager.js b/chrome/browser/resources/options/chromeos/display_layout_manager.js |
index f264393e5c7ea3fd388f3ffd6d490972524b41f6..17317ac111ba4b5c9658398ab6d35484ba3b0045 100644 |
--- a/chrome/browser/resources/options/chromeos/display_layout_manager.js |
+++ b/chrome/browser/resources/options/chromeos/display_layout_manager.js |
@@ -42,7 +42,7 @@ options.DisplayPosition; |
* layoutType: options.DisplayLayoutType, |
* name: string, |
* offset: number, |
- * originalPosition: !options.DisplayPosition, |
+ * originalDivOffsets: !options.DisplayPosition, |
* parentId: string |
* }} |
*/ |
@@ -57,7 +57,7 @@ cr.define('options', function() { |
* @param {!options.DisplayPosition} point The point to check the position. |
* @return {options.DisplayLayoutType} |
*/ |
- function getPositionToRectangle(rect, point) { |
+ function getLayoutTypeForPosition(rect, point) { |
// Separates the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of |
// the rect, and decides which area the display should reside. |
var diagonalSlope = rect.height / rect.width; |
@@ -78,30 +78,22 @@ cr.define('options', function() { |
} |
/** |
- * Snaps the region [point, width] to [basePoint, baseWidth] if |
- * the [point, width] is close enough to the base's edge. |
- * @param {number} point The starting point of the region. |
- * @param {number} width The width of the region. |
- * @param {number} basePoint The starting point of the base region. |
- * @param {number} baseWidth The width of the base region. |
- * @return {number} The moved point. Returns the point itself if it doesn't |
- * need to snap to the edge. |
- * @private |
+ * @param {options.DisplayLayoutType} layoutType |
+ * @return {!options.DisplayLayoutType} |
*/ |
- function snapToEdge(point, width, basePoint, baseWidth) { |
- // If the edge of the region is smaller than this, it will snap to the |
- // base's edge. |
- /** @const */ var SNAP_DISTANCE_PX = 16; |
- |
- var startDiff = Math.abs(point - basePoint); |
- var endDiff = Math.abs(point + width - (basePoint + baseWidth)); |
- // Prefer the closer one if both edges are close enough. |
- if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) |
- return basePoint; |
- else if (endDiff < SNAP_DISTANCE_PX) |
- return basePoint + baseWidth - width; |
- |
- return point; |
+ function invertLayoutType(layoutType) { |
+ switch (layoutType) { |
+ case options.DisplayLayoutType.RIGHT: |
+ return options.DisplayLayoutType.LEFT; |
+ case options.DisplayLayoutType.LEFT: |
+ return options.DisplayLayoutType.RIGHT; |
+ case options.DisplayLayoutType.TOP: |
+ return options.DisplayLayoutType.BOTTOM; |
+ case options.DisplayLayoutType.BOTTOM: |
+ return options.DisplayLayoutType.TOP; |
+ } |
+ assertNotReached(); |
+ return layoutType; |
} |
/** |
@@ -139,6 +131,29 @@ cr.define('options', function() { |
displayAreaOffset_: null, |
/** |
+ * Creates a DisplayLayout object representing the display. |
+ * @param {string} id |
+ * @param {string} name |
+ * @param {options.DisplayBounds} bounds |
+ * @param {!options.DisplayLayoutType} layoutType |
+ * @param {string} parentId |
+ * @return {!options.DisplayLayout} |
+ * @private |
+ */ |
+ createDisplayLayout: function(id, name, bounds, layoutType, parentId) { |
+ return { |
+ bounds: bounds, |
+ div: null, |
+ id: id, |
+ layoutType: layoutType, |
+ name: name, |
+ offset: 0, |
+ originalDivOffsets: {x: 0, y: 0}, |
+ parentId: parentId |
+ }; |
+ }, |
+ |
+ /** |
* Adds a display to the layout map. |
* @param {options.DisplayLayout} displayLayout |
*/ |
@@ -236,10 +251,10 @@ cr.define('options', function() { |
var baseLayout = this.getBaseLayout_(displayLayout); |
var baseDiv = baseLayout.div; |
- newPosition.x = snapToEdge( |
+ newPosition.x = this.snapToEdge_( |
newPosition.x, div.offsetWidth, baseDiv.offsetLeft, |
baseDiv.offsetWidth); |
- newPosition.y = snapToEdge( |
+ newPosition.y = this.snapToEdge_( |
newPosition.y, div.offsetHeight, baseDiv.offsetTop, |
baseDiv.offsetHeight); |
@@ -259,86 +274,38 @@ cr.define('options', function() { |
// a single parent with one child. |
var isPrimary = displayLayout.parentId == ''; |
- // layoutType is always stored in the child layout. |
- var layoutType = |
- isPrimary ? baseLayout.layoutType : displayLayout.layoutType; |
- |
- switch (getPositionToRectangle(baseBounds, newCenter)) { |
- case options.DisplayLayoutType.RIGHT: |
- layoutType = isPrimary ? options.DisplayLayoutType.LEFT : |
- options.DisplayLayoutType.RIGHT; |
- break; |
- case options.DisplayLayoutType.LEFT: |
- layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : |
- options.DisplayLayoutType.LEFT; |
- break; |
- case options.DisplayLayoutType.TOP: |
- layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : |
- options.DisplayLayoutType.TOP; |
- break; |
- case options.DisplayLayoutType.BOTTOM: |
- layoutType = isPrimary ? options.DisplayLayoutType.TOP : |
- options.DisplayLayoutType.BOTTOM; |
- break; |
- } |
+ var layoutType = getLayoutTypeForPosition(baseBounds, newCenter); |
+ if (isPrimary) |
+ layoutType = invertLayoutType(layoutType); |
if (layoutType == options.DisplayLayoutType.LEFT || |
layoutType == options.DisplayLayoutType.RIGHT) { |
- if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) |
+ if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) { |
layoutType = isPrimary ? options.DisplayLayoutType.TOP : |
options.DisplayLayoutType.BOTTOM; |
- else if (newPosition.y + div.offsetHeight < baseDiv.offsetTop) |
+ } else if (newPosition.y + div.offsetHeight < baseDiv.offsetTop) { |
layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : |
options.DisplayLayoutType.TOP; |
+ } |
} else { |
- if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth) |
+ if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth) { |
layoutType = isPrimary ? options.DisplayLayoutType.LEFT : |
options.DisplayLayoutType.RIGHT; |
- else if (newPosition.x + div.offsetWidth < baseDiv.offsetLeft) |
+ } else if (newPosition.x + div.offsetWidth < baseDiv.offsetLeft) { |
layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : |
options.DisplayLayoutType.LEFT; |
+ } |
} |
- var layoutToBase; |
- if (!isPrimary) { |
- displayLayout.layoutType = layoutType; |
- layoutToBase = layoutType; |
- } else { |
+ // layoutType is always stored in the child layout. |
+ if (isPrimary) |
baseLayout.layoutType = layoutType; |
- switch (layoutType) { |
- case options.DisplayLayoutType.RIGHT: |
- layoutToBase = options.DisplayLayoutType.LEFT; |
- break; |
- case options.DisplayLayoutType.LEFT: |
- layoutToBase = options.DisplayLayoutType.RIGHT; |
- break; |
- case options.DisplayLayoutType.TOP: |
- layoutToBase = options.DisplayLayoutType.BOTTOM; |
- break; |
- case options.DisplayLayoutType.BOTTOM: |
- layoutToBase = options.DisplayLayoutType.TOP; |
- break; |
- } |
- } |
+ else |
+ displayLayout.layoutType = layoutType; |
- switch (layoutToBase) { |
- case options.DisplayLayoutType.RIGHT: |
- div.style.left = baseDiv.offsetLeft + baseDiv.offsetWidth + 'px'; |
- div.style.top = newPosition.y + 'px'; |
- break; |
- case options.DisplayLayoutType.LEFT: |
- div.style.left = baseDiv.offsetLeft - div.offsetWidth + 'px'; |
- div.style.top = newPosition.y + 'px'; |
- break; |
- case options.DisplayLayoutType.TOP: |
- div.style.top = baseDiv.offsetTop - div.offsetHeight + 'px'; |
- div.style.left = newPosition.x + 'px'; |
- break; |
- case options.DisplayLayoutType.BOTTOM: |
- div.style.top = baseDiv.offsetTop + baseDiv.offsetHeight + 'px'; |
- div.style.left = newPosition.x + 'px'; |
- break; |
- } |
+ var layoutToBase = isPrimary ? invertLayoutType(layoutType) : layoutType; |
+ |
+ this.setDivPosition_(div, newPosition, baseDiv, layoutToBase); |
}, |
/** |
@@ -348,42 +315,22 @@ cr.define('options', function() { |
* @return {boolean} True if the final position differs from the original. |
*/ |
finalizePosition: function(id) { |
- // Make sure the dragging location is connected. |
var displayLayout = this.displayLayoutMap_[id]; |
var div = displayLayout.div; |
var baseLayout = this.getBaseLayout_(displayLayout); |
- var baseDiv = baseLayout.div; |
var isPrimary = displayLayout.parentId == ''; |
var layoutType = |
isPrimary ? baseLayout.layoutType : displayLayout.layoutType; |
- // The number of pixels to share the edges between displays. |
- /** @const */ var MIN_OFFSET_OVERLAP = 5; |
- |
- if (layoutType == options.DisplayLayoutType.LEFT || |
- layoutType == options.DisplayLayoutType.RIGHT) { |
- var top = Math.max( |
- div.offsetTop, |
- baseDiv.offsetTop - div.offsetHeight + MIN_OFFSET_OVERLAP); |
- top = Math.min( |
- top, baseDiv.offsetTop + baseDiv.offsetHeight - MIN_OFFSET_OVERLAP); |
- div.style.top = top + 'px'; |
- } else { |
- var left = Math.max( |
- div.offsetLeft, |
- baseDiv.offsetLeft - div.offsetWidth + MIN_OFFSET_OVERLAP); |
- left = Math.min( |
- left, |
- baseDiv.offsetLeft + baseDiv.offsetWidth - MIN_OFFSET_OVERLAP); |
- div.style.left = left + 'px'; |
- } |
+ // Make sure the dragging location is connected. |
+ this.adjustCorners_(div, baseLayout.div, layoutType); |
// Calculate the offset of the child display. |
this.calculateOffset_(isPrimary ? baseLayout : displayLayout); |
- return displayLayout.originalPosition.x != div.offsetLeft || |
- displayLayout.originalPosition.y != div.offsetTop; |
+ return displayLayout.originalDivOffsets.x != div.offsetLeft || |
+ displayLayout.originalDivOffsets.y != div.offsetTop; |
}, |
/** |
@@ -442,7 +389,6 @@ cr.define('options', function() { |
createDisplayLayoutDiv_: function(id, displayAreaDiv) { |
var displayLayout = this.displayLayoutMap_[id]; |
var parentId = displayLayout.parentId; |
- var offset = this.displayAreaOffset_; |
if (parentId) { |
// Ensure the parent div is created first. |
var parentLayout = this.displayLayoutMap_[parentId]; |
@@ -452,6 +398,7 @@ cr.define('options', function() { |
var div = /** @type {!HTMLElement} */ (document.createElement('div')); |
div.className = 'displays-display'; |
+ displayLayout.div = div; |
// div needs to be added to the DOM tree first, otherwise offsetHeight for |
// nameContainer below cannot be computed. |
@@ -461,13 +408,31 @@ cr.define('options', function() { |
nameContainer.textContent = displayLayout.name; |
div.appendChild(nameContainer); |
- var bounds = displayLayout.bounds; |
- div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; |
- var newHeight = Math.floor(bounds.height * this.visualScale_); |
- div.style.height = newHeight + 'px'; |
+ var newHeight = |
+ Math.floor(displayLayout.bounds.height * this.visualScale_); |
nameContainer.style.marginTop = |
(newHeight - nameContainer.offsetHeight) / 2 + 'px'; |
+ this.layoutDivFromBounds_(displayLayout); |
+ |
+ displayLayout.originalDivOffsets.x = div.offsetLeft; |
+ displayLayout.originalDivOffsets.y = div.offsetTop; |
+ |
+ this.calculateOffset_(displayLayout); |
+ }, |
+ |
+ /** |
+ * Calculates the div layout for displayLayout. |
+ * @param {options.DisplayLayout} displayLayout |
+ */ |
+ layoutDivFromBounds_: function(displayLayout) { |
+ var div = displayLayout.div; |
+ var bounds = displayLayout.bounds; |
+ |
+ div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; |
+ div.style.height = Math.floor(bounds.height * this.visualScale_) + 'px'; |
+ |
+ var offset = this.displayAreaOffset_; |
if (displayLayout.parentId == '') { |
div.style.left = |
Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
@@ -503,15 +468,10 @@ cr.define('options', function() { |
} |
} |
- displayLayout.div = div; |
- displayLayout.originalPosition.x = div.offsetLeft; |
- displayLayout.originalPosition.y = div.offsetTop; |
- |
- this.calculateOffset_(displayLayout); |
}, |
/** |
- * Calculates the offset for display |id| relative to its parent. |
+ * Calculates the offset for displayLayout relative to its parent. |
* @param {options.DisplayLayout} displayLayout |
*/ |
calculateOffset_: function(displayLayout) { |
@@ -548,6 +508,101 @@ cr.define('options', function() { |
} |
assertNotReached(); |
return null; |
+ }, |
+ |
+ /** |
+ * Update the location |div| to the position closest to |newPosition| along |
+ * the edge of |parentDiv| specified by |layoutType|. |
+ * @param {?HTMLElement} div |
+ * @param {options.DisplayPosition} newPosition |
+ * @param {?HTMLElement} parentDiv |
+ * @param {!options.DisplayLayoutType} layoutType |
+ * @private |
+ */ |
+ setDivPosition_(div, newPosition, parentDiv, layoutType) { |
+ switch (layoutType) { |
+ case options.DisplayLayoutType.RIGHT: |
+ div.style.left = parentDiv.offsetLeft + parentDiv.offsetWidth + 'px'; |
+ div.style.top = newPosition.y + 'px'; |
+ break; |
+ case options.DisplayLayoutType.LEFT: |
+ div.style.left = parentDiv.offsetLeft - div.offsetWidth + 'px'; |
+ div.style.top = newPosition.y + 'px'; |
+ break; |
+ case options.DisplayLayoutType.TOP: |
+ div.style.top = parentDiv.offsetTop - div.offsetHeight + 'px'; |
+ div.style.left = newPosition.x + 'px'; |
+ break; |
+ case options.DisplayLayoutType.BOTTOM: |
+ div.style.top = parentDiv.offsetTop + parentDiv.offsetHeight + 'px'; |
+ div.style.left = newPosition.x + 'px'; |
+ break; |
+ } |
+ }, |
+ |
+ /** |
+ * Snaps the region [point, width] to [basePoint, baseWidth] if |
+ * the [point, width] is close enough to the base's edge. |
+ * @param {number} point The starting point of the region. |
+ * @param {number} width The width of the region. |
+ * @param {number} basePoint The starting point of the base region. |
+ * @param {number} baseWidth The width of the base region. |
+ * @param {number} opt_snapDistance Provide to override the snap distance. |
+ * 0 means snap at any distance. |
+ * @return {number} The moved point. Returns the point itself if it doesn't |
+ * need to snap to the edge. |
+ * @private |
+ */ |
+ snapToEdge_: function( |
+ point, width, basePoint, baseWidth, opt_snapDistance) { |
+ // If the edge of the region is smaller than this, it will snap to the |
+ // base's edge. |
+ /** @const */ var SNAP_DISTANCE_PX = 16; |
+ var snapDist; |
+ if (opt_snapDistance !== undefined) |
+ snapDist = opt_snapDistance; |
+ else |
+ snapDist = SNAP_DISTANCE_PX; |
+ var startDiff = Math.abs(point - basePoint); |
+ var endDiff = Math.abs(point + width - (basePoint + baseWidth)); |
+ // Prefer the closer one if both edges are close enough. |
+ if ((!snapDist || startDiff < snapDist) && startDiff < endDiff) |
+ return basePoint; |
+ else if (!snapDist || endDiff < SNAP_DISTANCE_PX) |
+ return basePoint + baseWidth - width; |
+ |
+ return point; |
+ }, |
+ |
+ /** |
+ * Ensures that there is a minimum overlap when displays meet at a corner. |
+ * @param {?HTMLElement} div |
+ * @param {?HTMLElement} parentDiv |
+ * @param {options.DisplayLayoutType} layoutType |
+ * @private |
+ */ |
+ adjustCorners_: function(div, parentDiv, layoutType) { |
+ // The number of pixels to share the edges between displays. |
+ /** @const */ var MIN_OFFSET_OVERLAP = 5; |
+ |
+ if (layoutType == options.DisplayLayoutType.LEFT || |
+ layoutType == options.DisplayLayoutType.RIGHT) { |
+ var top = Math.max( |
+ div.offsetTop, |
+ parentDiv.offsetTop - div.offsetHeight + MIN_OFFSET_OVERLAP); |
+ top = Math.min( |
+ top, |
+ parentDiv.offsetTop + parentDiv.offsetHeight - MIN_OFFSET_OVERLAP); |
+ div.style.top = top + 'px'; |
+ } else { |
+ var left = Math.max( |
+ div.offsetLeft, |
+ parentDiv.offsetLeft - div.offsetWidth + MIN_OFFSET_OVERLAP); |
+ left = Math.min( |
+ left, |
+ parentDiv.offsetLeft + parentDiv.offsetWidth - MIN_OFFSET_OVERLAP); |
+ div.style.left = left + 'px'; |
+ } |
} |
}; |