| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Behavior for handling display layout, specifically | 6 * @fileoverview Behavior for handling display layout, specifically |
| 7 * edge snapping and collisions. | 7 * edge snapping and collisions. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 /** @polymerBehavior */ | 10 /** @polymerBehavior */ |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays | 51 * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays |
| 52 * @param {!Array<!chrome.system.display.DisplayLayout>} layouts | 52 * @param {!Array<!chrome.system.display.DisplayLayout>} layouts |
| 53 */ | 53 */ |
| 54 initializeDisplayLayout: function(displays, layouts) { | 54 initializeDisplayLayout: function(displays, layouts) { |
| 55 this.dragLayoutId = ''; | 55 this.dragLayoutId = ''; |
| 56 this.dragParentId_ = ''; | 56 this.dragParentId_ = ''; |
| 57 | 57 |
| 58 this.mirroring = displays.length > 0 && !!displays[0].mirroringSourceId; | 58 this.mirroring = displays.length > 0 && !!displays[0].mirroringSourceId; |
| 59 | 59 |
| 60 this.displayBoundsMap_.clear(); | 60 this.displayBoundsMap_.clear(); |
| 61 for (let display of displays) | 61 for (var i = 0; i < displays.length; ++i) { |
| 62 var display = displays[i]; |
| 62 this.displayBoundsMap_.set(display.id, display.bounds); | 63 this.displayBoundsMap_.set(display.id, display.bounds); |
| 63 | 64 } |
| 64 this.displayLayoutMap_.clear(); | 65 this.displayLayoutMap_.clear(); |
| 65 for (let layout of layouts) | 66 for (var j = 0; j < layouts.length; ++j) { |
| 67 var layout = layouts[j]; |
| 66 this.displayLayoutMap_.set(layout.id, layout); | 68 this.displayLayoutMap_.set(layout.id, layout); |
| 67 | 69 } |
| 68 this.calculatedBoundsMap_.clear(); | 70 this.calculatedBoundsMap_.clear(); |
| 69 for (let display of displays) { | 71 for (var k = 0; k < displays.length; ++k) { |
| 72 display = displays[k]; |
| 70 if (!this.calculatedBoundsMap_.has(display.id)) { | 73 if (!this.calculatedBoundsMap_.has(display.id)) { |
| 71 let bounds = display.bounds; | 74 var bounds = display.bounds; |
| 72 this.calculateBounds_(display.id, bounds.width, bounds.height); | 75 this.calculateBounds_(display.id, bounds.width, bounds.height); |
| 73 } | 76 } |
| 74 } | 77 } |
| 75 }, | 78 }, |
| 76 | 79 |
| 77 /** | 80 /** |
| 78 * Called when a drag event occurs. Checks collisions and updates the layout. | 81 * Called when a drag event occurs. Checks collisions and updates the layout. |
| 79 * @param {string} id | 82 * @param {string} id |
| 80 * @param {!chrome.system.display.Bounds} newBounds The new calculated | 83 * @param {!chrome.system.display.Bounds} newBounds The new calculated |
| 81 * bounds for the display. | 84 * bounds for the display. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 var layout = this.displayLayoutMap_.get(id); | 142 var layout = this.displayLayoutMap_.get(id); |
| 140 | 143 |
| 141 var orphanIds; | 144 var orphanIds; |
| 142 if (!layout || layout.parentId == '') { | 145 if (!layout || layout.parentId == '') { |
| 143 // Primary display. Set the calculated position to |dragBounds_|. | 146 // Primary display. Set the calculated position to |dragBounds_|. |
| 144 this.setCalculatedDisplayBounds_(id, this.dragBounds_); | 147 this.setCalculatedDisplayBounds_(id, this.dragBounds_); |
| 145 | 148 |
| 146 // We cannot re-parent the primary display, so instead make all other | 149 // We cannot re-parent the primary display, so instead make all other |
| 147 // displays orphans and clear their calculated bounds. | 150 // displays orphans and clear their calculated bounds. |
| 148 orphanIds = this.findChildren_(id, true /* recurse */); | 151 orphanIds = this.findChildren_(id, true /* recurse */); |
| 149 for (let o in orphanIds) | |
| 150 this.calculatedBoundsMap_.delete(o); | |
| 151 | 152 |
| 152 // Re-parent |dragParentId_|. It will be forced to parent to the dragged | 153 // Re-parent |dragParentId_|. It will be forced to parent to the dragged |
| 153 // display since it is the only non-orphan. | 154 // display since it is the only non-orphan. |
| 154 this.reparentOrphan_(this.dragParentId_, orphanIds); | 155 this.reparentOrphan_(this.dragParentId_, orphanIds); |
| 155 orphanIds.splice(orphanIds.indexOf(this.dragParentId_), 1); | 156 orphanIds.splice(orphanIds.indexOf(this.dragParentId_), 1); |
| 156 } else { | 157 } else { |
| 157 // All immediate children of |layout| will need to be re-parented. | 158 // All immediate children of |layout| will need to be re-parented. |
| 158 orphanIds = this.findChildren_(id, false /* do not recurse */); | 159 orphanIds = this.findChildren_(id, false /* do not recurse */); |
| 159 for (let o in orphanIds) | |
| 160 this.calculatedBoundsMap_.delete(o); | |
| 161 | 160 |
| 162 // When re-parenting to a descendant, also parent any immediate child to | 161 // When re-parenting to a descendant, also parent any immediate child to |
| 163 // drag display's current parent. | 162 // drag display's current parent. |
| 164 var topLayout = this.displayLayoutMap_.get(this.dragParentId_); | 163 var topLayout = this.displayLayoutMap_.get(this.dragParentId_); |
| 165 while (topLayout && topLayout.parentId != '') { | 164 while (topLayout && topLayout.parentId != '') { |
| 166 if (topLayout.parentId == id) { | 165 if (topLayout.parentId == id) { |
| 167 topLayout.parentId = layout.parentId; | 166 topLayout.parentId = layout.parentId; |
| 168 break; | 167 break; |
| 169 } | 168 } |
| 170 topLayout = this.displayLayoutMap_.get(topLayout.parentId); | 169 topLayout = this.displayLayoutMap_.get(topLayout.parentId); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 Object.assign({}, bounds))); | 212 Object.assign({}, bounds))); |
| 214 }, | 213 }, |
| 215 | 214 |
| 216 /** | 215 /** |
| 217 * Re-parents all entries in |orphanIds| and any children. | 216 * Re-parents all entries in |orphanIds| and any children. |
| 218 * @param {!Array<string>} orphanIds The list of ids affected by the move. | 217 * @param {!Array<string>} orphanIds The list of ids affected by the move. |
| 219 * @private | 218 * @private |
| 220 */ | 219 */ |
| 221 updateOrphans_: function(orphanIds) { | 220 updateOrphans_: function(orphanIds) { |
| 222 var orphans = orphanIds.slice(); | 221 var orphans = orphanIds.slice(); |
| 223 for (let orphan of orphanIds) { | 222 for (var i = 0; i < orphanIds.length; ++i) { |
| 223 var orphan = orphanIds[i]; |
| 224 var newOrphans = this.findChildren_(orphan, true /* recurse */); | 224 var newOrphans = this.findChildren_(orphan, true /* recurse */); |
| 225 // If the dragged display was re-parented to one of its children, | 225 // If the dragged display was re-parented to one of its children, |
| 226 // there may be duplicates so merge the lists. | 226 // there may be duplicates so merge the lists. |
| 227 for (let o of newOrphans) { | 227 for (var ii = 0; ii < newOrphans.length; ++ii) { |
| 228 var o = newOrphans[ii]; |
| 228 if (!orphans.includes(o)) | 229 if (!orphans.includes(o)) |
| 229 orphans.push(o); | 230 orphans.push(o); |
| 230 } | 231 } |
| 231 } | 232 } |
| 232 | 233 |
| 233 // Remove each orphan from the list as it is re-parented so that | 234 // Remove each orphan from the list as it is re-parented so that |
| 234 // subsequent orphans can be parented to it. | 235 // subsequent orphans can be parented to it. |
| 235 while (orphans.length) { | 236 while (orphans.length) { |
| 236 var orphanId = orphans.shift(); | 237 var orphanId = orphans.shift(); |
| 237 this.reparentOrphan_(orphanId, orphans); | 238 this.reparentOrphan_(orphanId, orphans); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 }, | 286 }, |
| 286 | 287 |
| 287 /** | 288 /** |
| 288 * @param {string} parentId | 289 * @param {string} parentId |
| 289 * @param {boolean} recurse Include descendants of children. | 290 * @param {boolean} recurse Include descendants of children. |
| 290 * @return {!Array<string>} | 291 * @return {!Array<string>} |
| 291 * @private | 292 * @private |
| 292 */ | 293 */ |
| 293 findChildren_: function(parentId, recurse) { | 294 findChildren_: function(parentId, recurse) { |
| 294 var children = []; | 295 var children = []; |
| 295 for (let childId of this.displayLayoutMap_.keys()) { | 296 this.displayLayoutMap_.forEach(function(value, key) { |
| 296 if (childId == parentId) | 297 var childId = key; |
| 297 continue; | 298 if (childId != parentId && value.parentId == parentId) { |
| 298 if (this.displayLayoutMap_.get(childId).parentId == parentId) { | |
| 299 // Insert immediate children at the front of the array. | 299 // Insert immediate children at the front of the array. |
| 300 children.unshift(childId); | 300 children.unshift(childId); |
| 301 if (recurse) { | 301 if (recurse) { |
| 302 // Descendants get added to the end of the list. | 302 // Descendants get added to the end of the list. |
| 303 children = children.concat(this.findChildren_(childId, true)); | 303 children = children.concat(this.findChildren_(childId, true)); |
| 304 } | 304 } |
| 305 } | 305 } |
| 306 } | 306 }.bind(this)); |
| 307 return children; | 307 return children; |
| 308 }, | 308 }, |
| 309 | 309 |
| 310 /** | 310 /** |
| 311 * Recursively calculates the absolute bounds of a display. | 311 * Recursively calculates the absolute bounds of a display. |
| 312 * Caches the display bounds so that parent bounds are only calculated once. | 312 * Caches the display bounds so that parent bounds are only calculated once. |
| 313 * @param {string} id | 313 * @param {string} id |
| 314 * @param {number} width | 314 * @param {number} width |
| 315 * @param {number} height | 315 * @param {number} height |
| 316 * @private | 316 * @private |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 * @param {!chrome.system.display.Bounds} bounds | 363 * @param {!chrome.system.display.Bounds} bounds |
| 364 * @param {Array<string>=} opt_ignoreIds Ids to ignore. | 364 * @param {Array<string>=} opt_ignoreIds Ids to ignore. |
| 365 * @return {string} | 365 * @return {string} |
| 366 * @private | 366 * @private |
| 367 */ | 367 */ |
| 368 findClosest_: function(displayId, bounds, opt_ignoreIds) { | 368 findClosest_: function(displayId, bounds, opt_ignoreIds) { |
| 369 var x = bounds.left + bounds.width / 2; | 369 var x = bounds.left + bounds.width / 2; |
| 370 var y = bounds.top + bounds.height / 2; | 370 var y = bounds.top + bounds.height / 2; |
| 371 var closestId = ''; | 371 var closestId = ''; |
| 372 var closestDelta2 = 0; | 372 var closestDelta2 = 0; |
| 373 for (let otherId of this.calculatedBoundsMap_.keys()) { | 373 var keys = this.calculatedBoundsMap_.keys(); |
| 374 for (var iter = keys.next(); !iter.done; iter = keys.next()) { |
| 375 var otherId = iter.value; |
| 374 if (otherId == displayId) | 376 if (otherId == displayId) |
| 375 continue; | 377 continue; |
| 376 if (opt_ignoreIds && opt_ignoreIds.includes(otherId)) | 378 if (opt_ignoreIds && opt_ignoreIds.includes(otherId)) |
| 377 continue; | 379 continue; |
| 378 var otherBounds = this.getCalculatedDisplayBounds(otherId); | 380 var otherBounds = this.getCalculatedDisplayBounds(otherId); |
| 379 var left = otherBounds.left; | 381 var left = otherBounds.left; |
| 380 var top = otherBounds.top; | 382 var top = otherBounds.top; |
| 381 var width = otherBounds.width; | 383 var width = otherBounds.width; |
| 382 var height = otherBounds.height; | 384 var height = otherBounds.height; |
| 383 if (x >= left && x < left + width && y >= top && y < top + height) | 385 if (x >= left && x < left + width && y >= top && y < top + height) |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 * @param {!chrome.system.display.Bounds} bounds | 546 * @param {!chrome.system.display.Bounds} bounds |
| 545 * @param {!{x: number, y: number}} deltaPos | 547 * @param {!{x: number, y: number}} deltaPos |
| 546 */ | 548 */ |
| 547 collideAndModifyDelta_: function(id, bounds, deltaPos) { | 549 collideAndModifyDelta_: function(id, bounds, deltaPos) { |
| 548 var keys = this.calculatedBoundsMap_.keys(); | 550 var keys = this.calculatedBoundsMap_.keys(); |
| 549 var others = new Set(keys); | 551 var others = new Set(keys); |
| 550 others.delete(id); | 552 others.delete(id); |
| 551 var checkCollisions = true; | 553 var checkCollisions = true; |
| 552 while (checkCollisions) { | 554 while (checkCollisions) { |
| 553 checkCollisions = false; | 555 checkCollisions = false; |
| 554 for (let otherId of others) { | 556 var othersValues = others.values(); |
| 557 for (var iter = othersValues.next(); !iter.done; |
| 558 iter = othersValues.next()) { |
| 559 var otherId = iter.value; |
| 555 var otherBounds = this.getCalculatedDisplayBounds(otherId); | 560 var otherBounds = this.getCalculatedDisplayBounds(otherId); |
| 556 if (this.collideWithBoundsAndModifyDelta_( | 561 if (this.collideWithBoundsAndModifyDelta_( |
| 557 bounds, otherBounds, deltaPos)) { | 562 bounds, otherBounds, deltaPos)) { |
| 558 if (deltaPos.x == 0 && deltaPos.y == 0) | 563 if (deltaPos.x == 0 && deltaPos.y == 0) |
| 559 return; | 564 return; |
| 560 others.delete(otherId); | 565 others.delete(otherId); |
| 561 checkCollisions = true; | 566 checkCollisions = true; |
| 562 break; | 567 break; |
| 563 } | 568 } |
| 564 } | 569 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 584 (newY >= otherBounds.top + otherBounds.height)) { | 589 (newY >= otherBounds.top + otherBounds.height)) { |
| 585 return false; | 590 return false; |
| 586 } | 591 } |
| 587 | 592 |
| 588 // |deltaPos| should already be restricted to X or Y. This shortens the | 593 // |deltaPos| should already be restricted to X or Y. This shortens the |
| 589 // delta to stay outside the bounds, however it does not change the sign of | 594 // delta to stay outside the bounds, however it does not change the sign of |
| 590 // the delta, i.e. it does not "push" the point outside the bounds if | 595 // the delta, i.e. it does not "push" the point outside the bounds if |
| 591 // the point is already inside. | 596 // the point is already inside. |
| 592 if (Math.abs(deltaPos.x) > Math.abs(deltaPos.y)) { | 597 if (Math.abs(deltaPos.x) > Math.abs(deltaPos.y)) { |
| 593 deltaPos.y = 0; | 598 deltaPos.y = 0; |
| 594 let snapDeltaX; | 599 var snapDeltaX; |
| 595 if (deltaPos.x > 0) { | 600 if (deltaPos.x > 0) { |
| 596 let x = otherBounds.left - bounds.width; | 601 snapDeltaX = |
| 597 snapDeltaX = Math.max(0, x - bounds.left); | 602 Math.max(0, (otherBounds.left - bounds.width) - bounds.left); |
| 598 } else { | 603 } else { |
| 599 let x = otherBounds.left + otherBounds.width; | 604 snapDeltaX = |
| 600 snapDeltaX = Math.min(x - bounds.left, 0); | 605 Math.min(0, (otherBounds.left + otherBounds.width) - bounds.left); |
| 601 } | 606 } |
| 602 deltaPos.x = snapDeltaX; | 607 deltaPos.x = snapDeltaX; |
| 603 } else { | 608 } else { |
| 604 deltaPos.x = 0; | 609 deltaPos.x = 0; |
| 605 let snapDeltaY; | 610 var snapDeltaY; |
| 606 if (deltaPos.y > 0) { | 611 if (deltaPos.y > 0) { |
| 607 let y = otherBounds.top - bounds.height; | 612 snapDeltaY = |
| 608 snapDeltaY = Math.min(0, y - bounds.top); | 613 Math.min(0, (otherBounds.top - bounds.height) - bounds.top); |
| 609 } else if (deltaPos.y < 0) { | 614 } else if (deltaPos.y < 0) { |
| 610 let y = otherBounds.top + otherBounds.height; | 615 snapDeltaY = |
| 611 snapDeltaY = Math.max(y - bounds.top, 0); | 616 Math.max(0, (otherBounds.top + otherBounds.height) - bounds.top); |
| 612 } else { | 617 } else { |
| 613 snapDeltaY = 0; | 618 snapDeltaY = 0; |
| 614 } | 619 } |
| 615 deltaPos.y = snapDeltaY; | 620 deltaPos.y = snapDeltaY; |
| 616 } | 621 } |
| 617 | 622 |
| 618 return true; | 623 return true; |
| 619 }, | 624 }, |
| 620 | 625 |
| 621 /** | 626 /** |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 | 686 |
| 682 /** | 687 /** |
| 683 * Highlights the edge of the div associated with |id| based on | 688 * Highlights the edge of the div associated with |id| based on |
| 684 * |layoutPosition| and removes any other highlights. If |layoutPosition| is | 689 * |layoutPosition| and removes any other highlights. If |layoutPosition| is |
| 685 * undefined, removes all highlights. | 690 * undefined, removes all highlights. |
| 686 * @param {string} id | 691 * @param {string} id |
| 687 * @param {chrome.system.display.LayoutPosition|undefined} layoutPosition | 692 * @param {chrome.system.display.LayoutPosition|undefined} layoutPosition |
| 688 * @private | 693 * @private |
| 689 */ | 694 */ |
| 690 highlightEdge_: function(id, layoutPosition) { | 695 highlightEdge_: function(id, layoutPosition) { |
| 691 for (let layout of this.layouts) { | 696 for (var i = 0; i < this.layouts.length; ++i) { |
| 697 var layout = this.layouts[i]; |
| 692 var highlight = (layout.id == id) ? layoutPosition : undefined; | 698 var highlight = (layout.id == id) ? layoutPosition : undefined; |
| 693 var div = this.$$('#_' + layout.id); | 699 var div = this.$$('#_' + layout.id); |
| 694 div.classList.toggle( | 700 div.classList.toggle( |
| 695 'highlight-right', | 701 'highlight-right', |
| 696 highlight == chrome.system.display.LayoutPosition.RIGHT); | 702 highlight == chrome.system.display.LayoutPosition.RIGHT); |
| 697 div.classList.toggle( | 703 div.classList.toggle( |
| 698 'highlight-left', | 704 'highlight-left', |
| 699 highlight == chrome.system.display.LayoutPosition.LEFT); | 705 highlight == chrome.system.display.LayoutPosition.LEFT); |
| 700 div.classList.toggle( | 706 div.classList.toggle( |
| 701 'highlight-top', | 707 'highlight-top', |
| 702 highlight == chrome.system.display.LayoutPosition.TOP); | 708 highlight == chrome.system.display.LayoutPosition.TOP); |
| 703 div.classList.toggle( | 709 div.classList.toggle( |
| 704 'highlight-bottom', | 710 'highlight-bottom', |
| 705 highlight == chrome.system.display.LayoutPosition.BOTTOM); | 711 highlight == chrome.system.display.LayoutPosition.BOTTOM); |
| 706 } | 712 } |
| 707 }, | 713 }, |
| 708 }; | 714 }; |
| OLD | NEW |