Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Unified Diff: chrome/browser/resources/settings/device_page/layout_behavior.js

Issue 2090953007: MD Settings: Display: Reparent children of dragged displays (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@issue_547080_display_settings8b_collide
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/settings/device_page/layout_behavior.js
diff --git a/chrome/browser/resources/settings/device_page/layout_behavior.js b/chrome/browser/resources/settings/device_page/layout_behavior.js
index ccc2c32865f307aa268ada9ab91ba7a3a38fed0a..51ba51bd83342f9380b855e19f5a23c19e4c0dcc 100644
--- a/chrome/browser/resources/settings/device_page/layout_behavior.js
+++ b/chrome/browser/resources/settings/device_page/layout_behavior.js
@@ -80,10 +80,14 @@ var LayoutBehavior = {
var closestId = this.findClosest_(id, newBounds);
// Find the closest edge.
- var layoutPosition = this.getLayoutPositionForBounds_(newBounds, closestId);
+ var closestBounds = this.getCalculatedDisplayBounds(closestId);
+ var layoutPosition =
+ this.getLayoutPositionForBounds_(newBounds, closestBounds);
// Snap to the closest edge.
- this.snapBounds_(closestId, layoutPosition, newBounds);
+ var snapPos = this.snapBounds_(newBounds, closestId, layoutPosition);
+ newBounds.left = snapPos.x;
+ newBounds.top = snapPos.y;
// Calculate the new bounds and delta.
var oldBounds = this.dragBounds_ || this.getCalculatedDisplayBounds(id);
@@ -122,13 +126,50 @@ var LayoutBehavior = {
!this.dragLayoutPosition_) {
return;
}
+
var layout = this.displayLayoutMap_.get(id);
- if (!layout)
- return;
- // Note: This updates layout in this.displayLayoutMap_ which is also the
- // entry in this.layouts.
- this.updateOffsetAndPosition_(
- this.dragBounds_, this.dragLayoutPosition_, layout);
+
+ var orphanIds;
+ if (!layout || layout.parentId == '') {
+ // Primary display. Set the calculated position to |dragBounds_|.
+ this.setCalculatedDisplayBounds_(id, this.dragBounds_);
+
+ // We cannot re-parent the primary display, so instead make all other
+ // displays orphans and clear their calculated bounds.
+ orphanIds = this.findChildren_(id, true /* recurse */);
+ for (let o in orphanIds)
+ this.calculatedBoundsMap_.delete(o);
+
+ // Re-parent |dragParentId_|. It will be forced to parent to the dragged
+ // display since it is the only non-orphan.
+ this.reparentOrphan_(this.dragParentId_, orphanIds);
+ orphanIds.splice(orphanIds.indexOf(this.dragParentId_), 1);
+ } else {
+ // All immediate children of |layout| will need to be re-parented.
+ orphanIds = this.findChildren_(id, false /* do not recurse */);
+ for (let o in orphanIds)
+ this.calculatedBoundsMap_.delete(o);
+
+ // When re-parenting to a descendant, also parent any immediate child to
+ // drag display's current parent.
+ var topLayout = this.displayLayoutMap_.get(this.dragParentId_);
+ while (topLayout && topLayout.parentId != '') {
+ if (topLayout.parentId == id) {
+ topLayout.parentId = layout.parentId;
+ break;
+ }
+ topLayout = this.displayLayoutMap_.get(topLayout.parentId);
+ }
+
+ // Re-parent the dragged display.
+ layout.parentId = this.dragParentId_;
+ this.updateOffsetAndPosition_(
+ this.dragBounds_, this.dragLayoutPosition_, layout);
+ }
+
+ // Update any orphaned children. This may cause the dragged display to
+ // be re-attached if it was attached to a child.
+ this.updateOrphans_(orphanIds);
// Send the updated layouts.
chrome.system.display.setDisplayLayout(this.layouts, function() {
@@ -163,7 +204,101 @@ var LayoutBehavior = {
},
/**
- * Recursively calculate the absolute bounds of a display.
+ * Re-parents all entries in |orphanIds| and any children.
+ * @param {!Array<string>} orphanIds The list of ids affected by the move.
+ * @private
+ */
+ updateOrphans_: function(orphanIds) {
+ var orphans = orphanIds.slice();
+ for (let orphan of orphanIds) {
+ var newOrphans = this.findChildren_(orphan, true /* recurse */);
+ // If the dragged display was re-parented to one of its children,
+ // there may be duplicates so merge the lists.
+ for (let o of newOrphans) {
+ if (!orphans.includes(o))
+ orphans.push(o);
+ }
+ }
+
+ // Remove each orphan from the list as it is re-parented so that
+ // subsequent orphans can be parented to it.
+ while (orphans.length) {
+ var orphanId = orphans.shift();
+ this.reparentOrphan_(orphanId, orphans);
+ }
+ },
+
+ /**
+ * Re-parents the orphan to a layout that is not a member of
+ * |otherOrphanIds|.
+ * @param {string} orphanId The id of the orphan to re-parent.
+ * @param {Array<string>} otherOrphanIds The list of ids of other orphans
+ * to ignore when re-parenting.
+ * @private
+ */
+ reparentOrphan_: function(orphanId, otherOrphanIds) {
+ var layout = this.displayLayoutMap_.get(orphanId);
+ assert(layout);
+ if (orphanId == this.dragId_ && layout.parentId != '') {
+ this.setCalculatedDisplayBounds_(orphanId, this.dragBounds_);
+ return;
+ }
+ var bounds = this.getCalculatedDisplayBounds(orphanId);
+
+ // Find the closest parent.
+ var newParentId = this.findClosest_(orphanId, bounds, otherOrphanIds);
+ assert(newParentId != '');
+ layout.parentId = newParentId;
+
+ // Find the closest edge.
+ var parentBounds = this.getCalculatedDisplayBounds(newParentId);
+ var layoutPosition = this.getLayoutPositionForBounds_(bounds, parentBounds);
+
+ // Move from the nearest corner to the desired location and get the delta.
+ var cornerBounds = this.getCornerBounds_(bounds, parentBounds);
+ var desiredPos = this.snapBounds_(bounds, newParentId, layoutPosition);
+ var deltaPos = {
+ x: desiredPos.x - cornerBounds.left,
+ y: desiredPos.y - cornerBounds.top
+ };
+
+ // Check for collisions.
+ this.collideAndModifyDelta_(orphanId, cornerBounds, deltaPos);
+ var desiredBounds = {
+ left: cornerBounds.left + deltaPos.x,
+ top: cornerBounds.top + deltaPos.y,
+ width: bounds.width,
+ height: bounds.height
+ };
+
+ this.updateOffsetAndPosition_(desiredBounds, layoutPosition, layout);
+ },
+
+ /**
+ * @param {string} parentId
+ * @param {boolean} recurse Include descendants of children.
+ * @return {!Array<string>}
+ * @private
+ */
+ findChildren_: function(parentId, recurse) {
+ var children = [];
+ for (let childId of this.displayLayoutMap_.keys()) {
+ if (childId == parentId)
+ continue;
+ if (this.displayLayoutMap_.get(childId).parentId == parentId) {
+ // Insert immediate children at the front of the array.
+ children.unshift(childId);
+ if (recurse) {
+ // Descendants get added to the end of the list.
+ children = children.concat(this.findChildren_(childId, true));
+ }
+ }
+ }
+ return children;
+ },
+
+ /**
+ * Recursively calculates the absolute bounds of a display.
* Caches the display bounds so that parent bounds are only calculated once.
* @param {string} id
* @param {number} width
@@ -262,22 +397,21 @@ var LayoutBehavior = {
/**
* Calculates the LayoutPosition for |bounds| relative to |parentId|.
* @param {!chrome.system.display.Bounds} bounds
- * @param {string} parentId
+ * @param {!chrome.system.display.Bounds} parentBounds
* @return {!chrome.system.display.LayoutPosition}
*/
- getLayoutPositionForBounds_: function(bounds, parentId) {
+ getLayoutPositionForBounds_: function(bounds, parentBounds) {
// Translate bounds from top-left to center.
var x = bounds.left + bounds.width / 2;
var y = bounds.top + bounds.height / 2;
// Determine the distance from the new bounds to both of the near edges.
- var parentBounds = this.getCalculatedDisplayBounds(parentId);
var left = parentBounds.left;
var top = parentBounds.top;
var width = parentBounds.width;
var height = parentBounds.height;
- // Signed deltas to the center of the div.
+ // Signed deltas to the center.
var dx = x - (left + width / 2);
var dy = y - (top + height / 2);
@@ -299,13 +433,14 @@ var LayoutBehavior = {
},
/**
- * Modifes |bounds| to the position closest to it along the edge of |parentId|
- * specified by |layoutPosition|.
+ * Modifies |bounds| to the position closest to it along the edge of
+ * |parentId| specified by |layoutPosition|.
+ * @param {!chrome.system.display.Bounds} bounds
* @param {string} parentId
* @param {!chrome.system.display.LayoutPosition} layoutPosition
- * @param {!chrome.system.display.Bounds} bounds
+ * @return {!{x: number, y: number}}
*/
- snapBounds_: function(parentId, layoutPosition, bounds) {
+ snapBounds_: function(bounds, parentId, layoutPosition) {
var parentBounds = this.getCalculatedDisplayBounds(parentId);
var x;
@@ -326,8 +461,7 @@ var LayoutBehavior = {
y = this.snapToY_(bounds, parentBounds);
}
- bounds.left = x;
- bounds.top = y;
+ return {x: x, y: y};
},
/**
@@ -510,6 +644,32 @@ var LayoutBehavior = {
},
/**
+ * Returns |bounds| translated to touch the closest corner of |parentBounds|.
+ * @param {!chrome.system.display.Bounds} bounds
+ * @param {!chrome.system.display.Bounds} parentBounds
+ * @return {!chrome.system.display.Bounds}
+ * @private
+ */
+ getCornerBounds_: function(bounds, parentBounds) {
+ var x;
+ if (bounds.left > parentBounds.left + parentBounds.width / 2)
+ x = parentBounds.left + parentBounds.width;
+ else
+ x = parentBounds.left - bounds.width;
+ var y;
+ if (bounds.top > parentBounds.top + parentBounds.height / 2)
+ y = parentBounds.top + parentBounds.height;
+ else
+ y = parentBounds.top - bounds.height;
+ return {
+ left: x,
+ top: y,
+ width: bounds.width,
+ height: bounds.height,
+ };
+ },
+
+ /**
* Highlights the edge of the div associated with |id| based on
* |layoutPosition| and removes any other highlights. If |layoutPosition| is
* undefined, removes all highlights.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698