Chromium Code Reviews| Index: chrome/browser/resources/options/chromeos/display_options.js |
| diff --git a/chrome/browser/resources/options/chromeos/display_options.js b/chrome/browser/resources/options/chromeos/display_options.js |
| index fb3f4ca9da01540b00324b8e6089273178464da9..830215880b91df2ad6e97d64c2a8deb116865e5a 100644 |
| --- a/chrome/browser/resources/options/chromeos/display_options.js |
| +++ b/chrome/browser/resources/options/chromeos/display_options.js |
| @@ -73,18 +73,28 @@ options.ColorProfile; |
| * availableColorProfiles: !Array<!options.ColorProfile>, |
| * bounds: !options.DisplayBounds, |
| * colorProfileId: number, |
| - * div: ?Element, |
| * id: string, |
| * isInternal: boolean, |
| * isPrimary: boolean, |
| * resolutions: !Array<!options.DisplayMode>, |
| * name: string, |
| - * rotation: number, |
| - * originalPosition: ?options.DisplayPosition |
| + * rotation: number |
| * }} |
| */ |
| options.DisplayInfo; |
| +/** |
| + * @typedef {{ |
| + * bounds: !options.DisplayBounds, |
| + * div: ?HTMLElement, |
| + * id: string, |
| + * isPrimary: boolean, |
| + * name: string, |
| + * originalPosition: !options.DisplayPosition |
| + * }} |
| + */ |
| +options.DisplayLayout; |
| + |
| cr.define('options', function() { |
| var Page = cr.ui.pageManager.Page; |
| var PageManager = cr.ui.pageManager.PageManager; |
| @@ -163,7 +173,7 @@ cr.define('options', function() { |
| * @type {options.DisplayLayoutType} |
| * @private |
| */ |
| - layout_: options.DisplayLayoutType.RIGHT, |
| + layoutType_: options.DisplayLayoutType.RIGHT, |
| /** |
| * The array of current output displays. It also contains the display |
| @@ -174,34 +184,41 @@ cr.define('options', function() { |
| displays_: [], |
| /** |
| - * The index of the currently focused display, or -1 for none. |
| - * @type {number} |
| + * An object containing DisplayLayout objects for each entry in |displays_|. |
| + * @type {!Object<!options.DisplayLayout>} |
|
xiyuan
2016/01/22 16:46:06
Do we need to doc the key type as well?
e.g.
@t
stevenjb
2016/01/22 18:48:44
Object keys are actually always strings (even when
xiyuan
2016/01/22 18:55:28
I see. Thanks for the clarification.
|
| * @private |
| */ |
| - focusedIndex_: -1, |
| + displayLayoutMap_: {}, |
| /** |
| - * The primary display edit info. |
| - * @type {?options.DisplayInfo} |
| + * The id of the currently focused display, or empty for none. |
| + * @type {string} |
| * @private |
| */ |
| - primaryDisplay_: null, |
| + focusedId_: '', |
| /** |
| - * The secondary display edit info. |
| - * @type {?options.DisplayInfo} |
| + * The primary display id. |
| + * @type {string} |
| * @private |
| */ |
| - secondaryDisplay_: null, |
| + primaryDisplayId_: '', |
| + |
| + /** |
| + * The secondary display id. |
| + * @type {string} |
| + * @private |
| + */ |
| + secondaryDisplayId_: '', |
| /** |
| * Drag info. |
| - * @type {?{display: !options.DisplayInfo, |
| + * @type {?{displayId: string, |
| * originalLocation: !options.DisplayPosition, |
| * eventLocation: !options.DisplayPosition}} |
| * @private |
| */ |
| - dragging_: null, |
| + dragInfo_: null, |
| /** |
| * The container div element which contains all of the display rectangles. |
| @@ -251,28 +268,25 @@ cr.define('options', function() { |
| container.ontouchend = this.endDragging_.bind(this); |
| $('display-options-set-primary').onclick = (function() { |
| - chrome.send('setPrimary', [this.displays_[this.focusedIndex_].id]); |
| + chrome.send('setPrimary', [this.focusedId_]); |
| }).bind(this); |
| $('display-options-resolution-selection').onchange = (function(ev) { |
| - var display = this.displays_[this.focusedIndex_]; |
| + var display = this.getDisplayInfoFromId(this.focusedId_); |
| var resolution = display.resolutions[ev.target.value]; |
| - chrome.send('setDisplayMode', [display.id, resolution]); |
| + chrome.send('setDisplayMode', [this.focusedId_, resolution]); |
| }).bind(this); |
| $('display-options-orientation-selection').onchange = (function(ev) { |
| - var displayIndex = |
| - (this.focusedIndex_ == -1) ? 0 : this.focusedIndex_; |
| var rotation = parseInt(ev.target.value, 10); |
| - chrome.send('setRotation', [this.displays_[displayIndex].id, rotation]); |
| + chrome.send('setRotation', [this.focusedId_, rotation]); |
| }).bind(this); |
| $('display-options-color-profile-selection').onchange = (function(ev) { |
| - chrome.send('setColorProfile', [this.displays_[this.focusedIndex_].id, |
| - ev.target.value]); |
| + chrome.send('setColorProfile', [this.focusedId_, ev.target.value]); |
| }).bind(this); |
| $('selected-display-start-calibrating-overscan').onclick = (function() { |
| // Passes the target display ID. Do not specify it through URL hash, |
| // we do not care back/forward. |
| var displayOverscan = options.DisplayOverscan.getInstance(); |
| - displayOverscan.setDisplayId(this.displays_[this.focusedIndex_].id); |
| + displayOverscan.setDisplayId(this.focusedId_); |
| PageManager.showPageByName('displayOverscan'); |
| chrome.send('coreOptionsUserMetricsAction', |
| ['Options_DisplaySetOverscan']); |
| @@ -394,22 +408,33 @@ cr.define('options', function() { |
| }, |
| /** |
| + * @param {string} id |
| + * @return {options.DisplayInfo} |
| + */ |
| + getDisplayInfoFromId(id) { |
| + return this.displays_.find(function(display) { |
| + return display.id == id; |
| + }); |
| + }, |
| + |
| + /** |
| * Collects the current data and sends it to Chrome. |
| * @private |
| */ |
| - applyResult_: function() { |
| + sendDragResult_: function() { |
| // Offset is calculated from top or left edge. |
| - var primary = this.primaryDisplay_; |
| - var secondary = this.secondaryDisplay_; |
| + var primary = this.displayLayoutMap_[this.primaryDisplayId_]; |
| + var secondary = this.displayLayoutMap_[this.secondaryDisplayId_]; |
| var offset; |
| - if (this.layout_ == options.DisplayLayoutType.LEFT || |
| - this.layout_ == options.DisplayLayoutType.RIGHT) { |
| + if (this.layoutType_ == options.DisplayLayoutType.LEFT || |
| + this.layoutType_ == options.DisplayLayoutType.RIGHT) { |
| offset = secondary.div.offsetTop - primary.div.offsetTop; |
| } else { |
| offset = secondary.div.offsetLeft - primary.div.offsetLeft; |
| } |
| offset = Math.floor(offset / this.visualScale_); |
| - chrome.send('setDisplayLayout', [secondary.id, this.layout_, offset]); |
| + chrome.send( |
| + 'setDisplayLayout', [secondary.id, this.layoutType_, offset]); |
| }, |
| /** |
| @@ -447,17 +472,7 @@ cr.define('options', function() { |
| * @private |
| */ |
| processDragging_: function(e, eventLocation) { |
| - if (!this.dragging_) |
| - return true; |
| - |
| - var index = -1; |
| - for (var i = 0; i < this.displays_.length; i++) { |
| - if (this.displays_[i] == this.dragging_.display) { |
| - index = i; |
| - break; |
| - } |
| - } |
| - if (index < 0) |
| + if (!this.dragInfo_) |
| return true; |
| e.preventDefault(); |
| @@ -465,82 +480,83 @@ cr.define('options', function() { |
| // Note that current code of moving display-rectangles doesn't work |
| // if there are >=3 displays. This is our assumption for M21. |
| // TODO(mukai): Fix the code to allow >=3 displays. |
| - var newPosition = { |
| - x: this.dragging_.originalLocation.x + |
| - (eventLocation.x - this.dragging_.eventLocation.x), |
| - y: this.dragging_.originalLocation.y + |
| - (eventLocation.y - this.dragging_.eventLocation.y) |
| + var dragInfo = this.dragInfo_; |
| + var dragLayout = this.displayLayoutMap_[dragInfo.displayId]; |
| + /** @type {options.DisplayPosition} */ var newPosition = { |
| + x: dragInfo.originalLocation.x + |
| + (eventLocation.x - dragInfo.eventLocation.x), |
| + y: dragInfo.originalLocation.y + |
| + (eventLocation.y - dragInfo.eventLocation.y) |
| }; |
| - var baseDiv = this.dragging_.display.isPrimary ? |
| - this.secondaryDisplay_.div : this.primaryDisplay_.div; |
| - var draggingDiv = this.dragging_.display.div; |
| + var baseDisplayId = dragLayout.isPrimary ? this.secondaryDisplayId_ : |
| + this.primaryDisplayId_; |
| + var baseDiv = this.displayLayoutMap_[baseDisplayId].div; |
| + var draggingDiv = dragLayout.div; |
| newPosition.x = this.snapToEdge_(newPosition.x, draggingDiv.offsetWidth, |
| baseDiv.offsetLeft, baseDiv.offsetWidth); |
| newPosition.y = this.snapToEdge_(newPosition.y, draggingDiv.offsetHeight, |
| baseDiv.offsetTop, baseDiv.offsetHeight); |
| - var newCenter = /** {!options.DisplayPosition} */({ |
| + /** @type {!options.DisplayPosition} */ var newCenter = { |
| x: newPosition.x + draggingDiv.offsetWidth / 2, |
| y: newPosition.y + draggingDiv.offsetHeight / 2 |
| - }); |
| + }; |
| - var baseBounds = /** {!options.DisplayBounds} */({ |
| + /** @type {!options.DisplayBounds} */ var baseBounds = { |
| left: baseDiv.offsetLeft, |
| top: baseDiv.offsetTop, |
| width: baseDiv.offsetWidth, |
| height: baseDiv.offsetHeight |
| - }); |
| + }; |
| + |
| + var isPrimary = dragLayout.isPrimary; |
| + var layoutType = this.layoutType_; |
| + |
| switch (getPositionToRectangle(baseBounds, newCenter)) { |
| case options.DisplayLayoutType.RIGHT: |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.LEFT : |
| - options.DisplayLayoutType.RIGHT; |
| + layoutType = isPrimary ? options.DisplayLayoutType.LEFT : |
| + options.DisplayLayoutType.RIGHT; |
| break; |
| case options.DisplayLayoutType.LEFT: |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.RIGHT : |
| - options.DisplayLayoutType.LEFT; |
| + layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : |
| + options.DisplayLayoutType.LEFT; |
| break; |
| case options.DisplayLayoutType.TOP: |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.BOTTOM : |
| - options.DisplayLayoutType.TOP; |
| + layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : |
| + options.DisplayLayoutType.TOP; |
| break; |
| case options.DisplayLayoutType.BOTTOM: |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.TOP : |
| - options.DisplayLayoutType.BOTTOM; |
| + layoutType = isPrimary ? options.DisplayLayoutType.TOP : |
| + options.DisplayLayoutType.BOTTOM; |
| break; |
| } |
| - if (this.layout_ == options.DisplayLayoutType.LEFT || |
| - this.layout_ == options.DisplayLayoutType.RIGHT) { |
| + if (layoutType == options.DisplayLayoutType.LEFT || |
| + layoutType == options.DisplayLayoutType.RIGHT) { |
| if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.TOP : |
| - options.DisplayLayoutType.BOTTOM; |
| + layoutType = isPrimary ? options.DisplayLayoutType.TOP : |
| + options.DisplayLayoutType.BOTTOM; |
| else if (newPosition.y + draggingDiv.offsetHeight < baseDiv.offsetTop) |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.BOTTOM : |
| - options.DisplayLayoutType.TOP; |
| + layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : |
| + options.DisplayLayoutType.TOP; |
| } else { |
| if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth) |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.LEFT : |
| - options.DisplayLayoutType.RIGHT; |
| + layoutType = isPrimary ? options.DisplayLayoutType.LEFT : |
| + options.DisplayLayoutType.RIGHT; |
| else if (newPosition.x + draggingDiv.offsetWidth < baseDiv.offsetLeft) |
| - this.layout_ = this.dragging_.display.isPrimary ? |
| - options.DisplayLayoutType.RIGHT : |
| - options.DisplayLayoutType.LEFT; |
| + layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : |
| + options.DisplayLayoutType.LEFT; |
| } |
| + this.layoutType_ = layoutType; |
| + |
| var layoutToBase; |
| - if (!this.dragging_.display.isPrimary) { |
| - layoutToBase = this.layout_; |
| + if (!isPrimary) { |
| + layoutToBase = layoutType; |
| } else { |
| - switch (this.layout_) { |
| + switch (layoutType) { |
| case options.DisplayLayoutType.RIGHT: |
| layoutToBase = options.DisplayLayoutType.LEFT; |
| break; |
| @@ -589,34 +605,38 @@ cr.define('options', function() { |
| * @private |
| */ |
| startDragging_: function(target, eventLocation) { |
| - var oldFocusedIndex = this.focusedIndex_; |
| + var oldFocusedId = this.focusedId_; |
| + var newFocusedId; |
| var willUpdateDisplayDescription = false; |
| - this.focusedIndex_ = -1; |
| for (var i = 0; i < this.displays_.length; i++) { |
| - var display = this.displays_[i]; |
| - if (display.div == target || |
| - (target.offsetParent && target.offsetParent == display.div)) { |
| - this.focusedIndex_ = i; |
| - if (oldFocusedIndex !== null && oldFocusedIndex != i) |
| - willUpdateDisplayDescription = true; |
| + var displayLayout = this.displayLayoutMap_[this.displays_[i].id]; |
| + if (displayLayout.div == target || |
| + (target.offsetParent && target.offsetParent == displayLayout.div)) { |
| + newFocusedId = displayLayout.id; |
| break; |
| } |
| } |
| + if (!newFocusedId) |
| + return false; |
| + |
| + this.focusedId_ = newFocusedId; |
| + willUpdateDisplayDescription = newFocusedId != oldFocusedId; |
| for (var i = 0; i < this.displays_.length; i++) { |
| - var display = this.displays_[i]; |
| - display.div.className = 'displays-display'; |
| - if (i != this.focusedIndex_) |
| + var displayLayout = this.displayLayoutMap_[this.displays_[i].id]; |
| + displayLayout.div.className = 'displays-display'; |
| + if (displayLayout.id != this.focusedId_) |
| continue; |
| - display.div.classList.add('displays-focused'); |
| + displayLayout.div.classList.add('displays-focused'); |
| if (this.displays_.length > 1) { |
| - this.dragging_ = { |
| - display: display, |
| + this.dragInfo_ = { |
| + displayId: displayLayout.id, |
| originalLocation: { |
| - x: display.div.offsetLeft, y: display.div.offsetTop |
| + x: displayLayout.div.offsetLeft, |
| + y: displayLayout.div.offsetTop |
| }, |
| - eventLocation: eventLocation |
| + eventLocation: {x: eventLocation.x, y: eventLocation.y} |
| }; |
| } |
| } |
| @@ -633,36 +653,39 @@ cr.define('options', function() { |
| */ |
| endDragging_: function(e) { |
| this.lastTouchLocation_ = null; |
| - if (this.dragging_) { |
| - // Make sure the dragging location is connected. |
| - var baseDiv = this.dragging_.display.isPrimary ? |
| - this.secondaryDisplay_.div : |
| - this.primaryDisplay_.div; |
| - var draggingDiv = this.dragging_.display.div; |
| - if (this.layout_ == options.DisplayLayoutType.LEFT || |
| - this.layout_ == options.DisplayLayoutType.RIGHT) { |
| - var top = Math.max( |
| - draggingDiv.offsetTop, baseDiv.offsetTop - |
| - draggingDiv.offsetHeight + MIN_OFFSET_OVERLAP); |
| - top = Math.min( |
| - top, |
| - baseDiv.offsetTop + baseDiv.offsetHeight - MIN_OFFSET_OVERLAP); |
| - draggingDiv.style.top = top + 'px'; |
| - } else { |
| - var left = Math.max( |
| - draggingDiv.offsetLeft, baseDiv.offsetLeft - |
| - draggingDiv.offsetWidth + MIN_OFFSET_OVERLAP); |
| - left = Math.min( |
| - left, |
| - baseDiv.offsetLeft + baseDiv.offsetWidth - MIN_OFFSET_OVERLAP); |
| - draggingDiv.style.left = left + 'px'; |
| - } |
| - var originalPosition = this.dragging_.display.originalPosition; |
| - if (originalPosition.x != draggingDiv.offsetLeft || |
| - originalPosition.y != draggingDiv.offsetTop) |
| - this.applyResult_(); |
| - this.dragging_ = null; |
| + if (!this.dragInfo_) |
| + return false; |
| + |
| + // Make sure the dragging location is connected. |
| + var dragLayout = this.displayLayoutMap_[this.dragInfo_.displayId]; |
| + var baseDisplayId = dragLayout.isPrimary ? this.secondaryDisplayId_ : |
| + this.primaryDisplayId_; |
| + var baseDiv = this.displayLayoutMap_[baseDisplayId].div; |
| + var draggingDiv = dragLayout.div; |
| + if (this.layoutType_ == options.DisplayLayoutType.LEFT || |
| + this.layoutType_ == options.DisplayLayoutType.RIGHT) { |
| + var top = Math.max( |
| + draggingDiv.offsetTop, |
| + baseDiv.offsetTop - draggingDiv.offsetHeight + MIN_OFFSET_OVERLAP); |
| + top = Math.min( |
| + top, baseDiv.offsetTop + baseDiv.offsetHeight - MIN_OFFSET_OVERLAP); |
| + draggingDiv.style.top = top + 'px'; |
| + } else { |
| + var left = Math.max( |
| + draggingDiv.offsetLeft, |
| + baseDiv.offsetLeft - draggingDiv.offsetWidth + MIN_OFFSET_OVERLAP); |
| + left = Math.min( |
| + left, |
| + baseDiv.offsetLeft + baseDiv.offsetWidth - MIN_OFFSET_OVERLAP); |
| + draggingDiv.style.left = left + 'px'; |
| + } |
| + if (dragLayout.originalPosition.x != draggingDiv.offsetLeft || |
| + dragLayout.originalPosition.y != draggingDiv.offsetTop) { |
| + this.sendDragResult_(); |
| } |
| + |
| + this.dragInfo_ = null; |
| + |
| return false; |
| }, |
| @@ -715,14 +738,15 @@ cr.define('options', function() { |
| * @private |
| */ |
| updateSelectedDisplaySectionForDisplay_: function(display) { |
| + var displayLayout = this.displayLayoutMap_[display.id]; |
| var arrow = $('display-configuration-arrow'); |
| arrow.hidden = false; |
| // Adding 1 px to the position to fit the border line and the border in |
| // arrow precisely. |
| arrow.style.top = $('display-configurations').offsetTop - |
| arrow.offsetHeight / 2 + 'px'; |
| - arrow.style.left = display.div.offsetLeft + |
| - display.div.offsetWidth / 2 - arrow.offsetWidth / 2 + 'px'; |
| + arrow.style.left = displayLayout.div.offsetLeft + |
| + displayLayout.div.offsetWidth / 2 - arrow.offsetWidth / 2 + 'px'; |
| $('display-options-set-primary').disabled = display.isPrimary; |
| $('display-options-select-mirroring').disabled = |
| @@ -804,12 +828,11 @@ cr.define('options', function() { |
| if (this.mirroring_) { |
| this.updateSelectedDisplaySectionMirroring_(); |
| - } else if (this.focusedIndex_ == -1 || |
| - this.displays_[this.focusedIndex_] == null) { |
| + } else if (this.focusedId_ == '') { |
| this.updateSelectedDisplaySectionNoSelected_(); |
| } else { |
| this.updateSelectedDisplaySectionForDisplay_( |
| - this.displays_[this.focusedIndex_]); |
| + this.getDisplayInfoFromId(this.focusedId_)); |
| } |
| }, |
| @@ -856,7 +879,7 @@ cr.define('options', function() { |
| $('display-options-displays-view').offsetWidth / 2 - totalWidth / 2; |
| for (var i = 0; i < numDisplays; i++) { |
| - var div = document.createElement('div'); |
| + var div = /** @type {HTMLElement} */ (document.createElement('div')); |
| div.className = 'displays-display'; |
| div.style.top = i * MIRRORING_OFFSET_PIXELS + 'px'; |
| div.style.left = i * MIRRORING_OFFSET_PIXELS + offsetX + 'px'; |
| @@ -867,20 +890,43 @@ cr.define('options', function() { |
| if (i != numDisplays - 1) |
| div.classList.add('display-mirrored'); |
| this.displaysView_.appendChild(div); |
| + |
| + // Not currently used but set for consistency / debugging. |
| + this.displayLayoutMap_[this.displays_[i].id].div = div; |
| } |
| }, |
| /** |
| + * Creates a DisplayLayout object representing the display. |
| + * @param {!options.DisplayInfo} display |
| + * @return {!options.DisplayLayout} |
| + * @private |
| + */ |
| + createDisplayLayout_: function(display) { |
| + /** @type {options.DisplayLayout} */ var displayLayout = { |
| + bounds: display.bounds, |
| + div: null, |
| + id: display.id, |
| + isPrimary: display.isPrimary, |
| + name: display.name, |
| + originalPosition: {x: 0, y: 0} |
| + }; |
| + return displayLayout; |
| + }, |
| + |
| + /** |
| * Creates a div element representing the specified display. |
| - * @param {!options.DisplayInfo} display The display object. |
| - * @param {boolean} focused True if it's focused. |
| + * @param {!options.DisplayLayout} displayLayout |
| + * @param {options.DisplayLayoutType} layoutType The layout type for the |
| + * secondary display. |
| + * @param {!options.DisplayPosition} offset The offset to the center of the |
| + * display area. |
| * @private |
| */ |
| - createDisplayRectangle_: function(display, focused) { |
| - var div = document.createElement('div'); |
| - display.div = div; |
| + createDisplayLayoutDiv_: function(displayLayout, layoutType, offset) { |
| + var div = /** @type {!HTMLElement} */ (document.createElement('div')); |
| div.className = 'displays-display'; |
| - if (focused) |
| + if (displayLayout.id == this.focusedId_) |
| div.classList.add('displays-focused'); |
|
xiyuan
2016/01/22 16:46:07
nit: div.classList.toggle('displays-focused', disp
stevenjb
2016/01/22 18:48:44
Done.
|
| // div needs to be added to the DOM tree first, otherwise offsetHeight for |
| @@ -888,39 +934,77 @@ cr.define('options', function() { |
| this.displaysView_.appendChild(div); |
| var nameContainer = document.createElement('div'); |
| - nameContainer.textContent = display.name; |
| + nameContainer.textContent = displayLayout.name; |
| div.appendChild(nameContainer); |
| - div.style.width = |
| - Math.floor(display.bounds.width * this.visualScale_) + 'px'; |
| - var newHeight = Math.floor(display.bounds.height * this.visualScale_); |
| + |
| + 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'; |
| nameContainer.style.marginTop = |
| (newHeight - nameContainer.offsetHeight) / 2 + 'px'; |
| div.onmousedown = this.onMouseDown_.bind(this); |
| div.ontouchstart = this.onTouchStart_.bind(this); |
| - return div; |
| + |
| + if (displayLayout.isPrimary) { |
| + div.style.left = |
| + Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| + div.style.top = |
| + Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| + } else { |
| + // Don't trust the secondary display's x or y, because it may cause a |
| + // 1px gap due to rounding, which will create a fake update on end |
| + // dragging. See crbug.com/386401 |
| + var primaryDiv = this.displayLayoutMap_[this.primaryDisplayId_].div; |
| + switch (layoutType) { |
| + case options.DisplayLayoutType.TOP: |
| + div.style.left = |
| + Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| + div.style.top = primaryDiv.offsetTop - div.offsetHeight + 'px'; |
| + break; |
| + case options.DisplayLayoutType.RIGHT: |
| + div.style.left = |
| + primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px'; |
| + div.style.top = |
| + Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| + break; |
| + case options.DisplayLayoutType.BOTTOM: |
| + div.style.left = |
| + Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| + div.style.top = |
| + primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px'; |
| + break; |
| + case options.DisplayLayoutType.LEFT: |
| + div.style.left = primaryDiv.offsetLeft - div.offsetWidth + 'px'; |
| + div.style.top = |
| + Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| + break; |
| + } |
| + } |
| + |
| + displayLayout.div = div; |
| + displayLayout.originalPosition.x = div.offsetLeft; |
| + displayLayout.originalPosition.y = div.offsetTop; |
| }, |
| /** |
| * Layouts the display rectangles according to the current layout_. |
| + * @param {options.DisplayLayoutType} layoutType |
| * @private |
| */ |
| - layoutDisplays_: function() { |
| + layoutDisplays_: function(layoutType) { |
| var maxWidth = 0; |
| var maxHeight = 0; |
| var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; |
| - this.primaryDisplay_ = null; |
| - this.secondaryDisplay_ = null; |
| - var focusedDisplay = null; |
| + this.primaryDisplayId_ = ''; |
| + this.secondaryDisplayId_ = ''; |
| for (var i = 0; i < this.displays_.length; i++) { |
| var display = this.displays_[i]; |
| if (display.isPrimary) |
| - this.primaryDisplay_ = display; |
| - else |
| - this.secondaryDisplay_ = display; |
| - if (i == this.focusedIndex_) |
| - focusedDisplay = display; |
| + this.primaryDisplayId_ = display.id; |
| + else if (this.secondaryDisplayId_ == '') |
| + this.secondaryDisplayId_ = display.id; |
| var bounds = display.bounds; |
| boundingBox.left = Math.min(boundingBox.left, bounds.left); |
| @@ -932,7 +1016,7 @@ cr.define('options', function() { |
| maxWidth = Math.max(maxWidth, bounds.width); |
| maxHeight = Math.max(maxHeight, bounds.height); |
| } |
| - if (!this.primaryDisplay_) |
| + if (this.primaryDisplayId_ == '') |
| return; |
| // Make the margin around the bounding box. |
| @@ -958,106 +1042,56 @@ cr.define('options', function() { |
| (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2) |
| }; |
| - // Layouting the display rectangles. First layout the primaryDisplay and |
| - // then layout the secondary which is attaching to the primary. |
| - var primaryDiv = this.createDisplayRectangle_( |
| - this.primaryDisplay_, this.primaryDisplay_ == focusedDisplay); |
| - primaryDiv.style.left = |
| - Math.floor(this.primaryDisplay_.bounds.left * this.visualScale_) + |
| - offset.x + 'px'; |
| - primaryDiv.style.top = |
| - Math.floor(this.primaryDisplay_.bounds.top * this.visualScale_) + |
| - offset.y + 'px'; |
| - this.primaryDisplay_.originalPosition = { |
| - x: primaryDiv.offsetLeft, |
| - y: primaryDiv.offsetTop |
| - }; |
| - |
| - if (this.secondaryDisplay_) { |
| - var secondaryDiv = this.createDisplayRectangle_( |
| - this.secondaryDisplay_, this.secondaryDisplay_ == focusedDisplay); |
| - // Don't trust the secondary display's x or y, because it may cause a |
| - // 1px gap due to rounding, which will create a fake update on end |
| - // dragging. See crbug.com/386401 |
| - var bounds = this.secondaryDisplay_.bounds; |
| - switch (this.layout_) { |
| - case options.DisplayLayoutType.TOP: |
| - secondaryDiv.style.left = |
| - Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| - secondaryDiv.style.top = |
| - primaryDiv.offsetTop - secondaryDiv.offsetHeight + 'px'; |
| - break; |
| - case options.DisplayLayoutType.RIGHT: |
| - secondaryDiv.style.left = |
| - primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px'; |
| - secondaryDiv.style.top = |
| - Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| - break; |
| - case options.DisplayLayoutType.BOTTOM: |
| - secondaryDiv.style.left = |
| - Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| - secondaryDiv.style.top = |
| - primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px'; |
| - break; |
| - case options.DisplayLayoutType.LEFT: |
| - secondaryDiv.style.left = |
| - primaryDiv.offsetLeft - secondaryDiv.offsetWidth + 'px'; |
| - secondaryDiv.style.top = |
| - Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| - break; |
| - } |
| - this.secondaryDisplay_.originalPosition = { |
| - x: secondaryDiv.offsetLeft, |
| - y: secondaryDiv.offsetTop |
| - }; |
| + // Layout the display rectangles. First layout the primary display and |
| + // then layout the secondary which is attached to the primary. |
| + for (var i = 0; i < this.displays_.length; i++) { |
| + this.createDisplayLayoutDiv_( |
| + this.displayLayoutMap_[this.displays_[i].id], layoutType, offset); |
| } |
| }, |
| /** |
| * Called when the display arrangement has changed. |
| * @param {options.MultiDisplayMode} mode multi display mode. |
| - * @param {Array<options.DisplayInfo>} displays The list of the display |
| + * @param {!Array<!options.DisplayInfo>} displays The list of the display |
| * information. |
| - * @param {options.DisplayLayoutType} layout The layout strategy. |
| + * @param {options.DisplayLayoutType} layoutType The layout strategy. |
| * @param {number} offset The offset of the secondary display. |
| * @private |
| */ |
| - onDisplayChanged_: function(mode, displays, layout, offset) { |
| + onDisplayChanged_: function(mode, displays, layoutType, offset) { |
| if (!this.visible) |
| return; |
| - var hasExternal = false; |
| + this.displays_ = displays; |
| + this.displayLayoutMap_ = {}; |
| for (var i = 0; i < displays.length; i++) { |
| - if (!displays[i].isInternal) { |
| - hasExternal = true; |
| - break; |
| - } |
| + var display = displays[i]; |
| + this.displayLayoutMap_[display.id] = this.createDisplayLayout_(display); |
| } |
| - this.layout_ = layout; |
| - |
| var mirroring = mode == options.MultiDisplayMode.MIRRORING; |
| var unifiedDesktopEnabled = mode == options.MultiDisplayMode.UNIFIED; |
| - // Focus to the first display next to the primary one when |displays| list |
| + // Focus to the first display next to the primary one when |displays_| |
| // is updated. |
| if (mirroring) { |
| - this.focusedIndex_ = -1; |
| - } else if (this.mirroring_ != mirroring || |
| - this.unifiedDesktopEnabled_ != unifiedDesktopEnabled || |
| - this.displays_.length != displays.length) { |
| - this.focusedIndex_ = 0; |
| + this.focusedId_ = ''; |
| + } else if ( |
| + this.focusedId_ == '' || this.mirroring_ != mirroring || |
| + this.unifiedDesktopEnabled_ != unifiedDesktopEnabled || |
| + this.displays_.length != displays.length) { |
| + this.focusedId_ = displays.length > 0 ? displays[0].id : ''; |
| } |
| this.mirroring_ = mirroring; |
| this.unifiedDesktopEnabled_ = unifiedDesktopEnabled; |
| - this.displays_ = displays; |
| this.resetDisplaysView_(); |
| if (this.mirroring_) |
| this.layoutMirroringDisplays_(); |
| else |
| - this.layoutDisplays_(); |
| + this.layoutDisplays_(layoutType); |
| $('display-options-select-mirroring').value = |
| mirroring ? 'mirroring' : 'extended'; |
| @@ -1081,9 +1115,9 @@ cr.define('options', function() { |
| }; |
| DisplayOptions.setDisplayInfo = function( |
| - mode, displays, layout, offset) { |
| + mode, displays, layoutType, offset) { |
| DisplayOptions.getInstance().onDisplayChanged_( |
| - mode, displays, layout, offset); |
| + mode, displays, layoutType, offset); |
| }; |
| // Export |