| 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 cr.exportPath('options'); | 5 cr.exportPath('options'); |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Enumeration of display layout. These values must match the C++ values in | 8 * Enumeration of display layout. These values must match the C++ values in |
| 9 * ash::DisplayController. | 9 * ash::DisplayController. |
| 10 * @enum {number} | 10 * @enum {number} |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 options.DisplayPosition; | 35 options.DisplayPosition; |
| 36 | 36 |
| 37 /** | 37 /** |
| 38 * @typedef {{ | 38 * @typedef {{ |
| 39 * bounds: !options.DisplayBounds, | 39 * bounds: !options.DisplayBounds, |
| 40 * div: ?HTMLElement, | 40 * div: ?HTMLElement, |
| 41 * id: string, | 41 * id: string, |
| 42 * layoutType: options.DisplayLayoutType, | 42 * layoutType: options.DisplayLayoutType, |
| 43 * name: string, | 43 * name: string, |
| 44 * offset: number, | 44 * offset: number, |
| 45 * originalPosition: !options.DisplayPosition, | 45 * originalDivOffsets: !options.DisplayPosition, |
| 46 * parentId: string | 46 * parentId: string |
| 47 * }} | 47 * }} |
| 48 */ | 48 */ |
| 49 options.DisplayLayout; | 49 options.DisplayLayout; |
| 50 | 50 |
| 51 cr.define('options', function() { | 51 cr.define('options', function() { |
| 52 'use strict'; | 52 'use strict'; |
| 53 | 53 |
| 54 /** | 54 /** |
| 55 * Gets the layout type of |point| relative to |rect|. | 55 * Gets the layout type of |point| relative to |rect|. |
| 56 * @param {!options.DisplayBounds} rect The base rectangle. | 56 * @param {!options.DisplayBounds} rect The base rectangle. |
| 57 * @param {!options.DisplayPosition} point The point to check the position. | 57 * @param {!options.DisplayPosition} point The point to check the position. |
| 58 * @return {options.DisplayLayoutType} | 58 * @return {options.DisplayLayoutType} |
| 59 */ | 59 */ |
| 60 function getPositionToRectangle(rect, point) { | 60 function getLayoutTypeForPosition(rect, point) { |
| 61 // Separates the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of | 61 // Separates the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of |
| 62 // the rect, and decides which area the display should reside. | 62 // the rect, and decides which area the display should reside. |
| 63 var diagonalSlope = rect.height / rect.width; | 63 var diagonalSlope = rect.height / rect.width; |
| 64 var topDownIntercept = rect.top - rect.left * diagonalSlope; | 64 var topDownIntercept = rect.top - rect.left * diagonalSlope; |
| 65 var bottomUpIntercept = rect.top + rect.height + rect.left * diagonalSlope; | 65 var bottomUpIntercept = rect.top + rect.height + rect.left * diagonalSlope; |
| 66 | 66 |
| 67 if (point.y > topDownIntercept + point.x * diagonalSlope) { | 67 if (point.y > topDownIntercept + point.x * diagonalSlope) { |
| 68 if (point.y > bottomUpIntercept - point.x * diagonalSlope) | 68 if (point.y > bottomUpIntercept - point.x * diagonalSlope) |
| 69 return options.DisplayLayoutType.BOTTOM; | 69 return options.DisplayLayoutType.BOTTOM; |
| 70 else | 70 else |
| 71 return options.DisplayLayoutType.LEFT; | 71 return options.DisplayLayoutType.LEFT; |
| 72 } else { | 72 } else { |
| 73 if (point.y > bottomUpIntercept - point.x * diagonalSlope) | 73 if (point.y > bottomUpIntercept - point.x * diagonalSlope) |
| 74 return options.DisplayLayoutType.RIGHT; | 74 return options.DisplayLayoutType.RIGHT; |
| 75 else | 75 else |
| 76 return options.DisplayLayoutType.TOP; | 76 return options.DisplayLayoutType.TOP; |
| 77 } | 77 } |
| 78 } | 78 } |
| 79 | 79 |
| 80 /** | 80 /** |
| 81 * Snaps the region [point, width] to [basePoint, baseWidth] if | 81 * @param {options.DisplayLayoutType} layoutType |
| 82 * the [point, width] is close enough to the base's edge. | 82 * @return {!options.DisplayLayoutType} |
| 83 * @param {number} point The starting point of the region. | |
| 84 * @param {number} width The width of the region. | |
| 85 * @param {number} basePoint The starting point of the base region. | |
| 86 * @param {number} baseWidth The width of the base region. | |
| 87 * @return {number} The moved point. Returns the point itself if it doesn't | |
| 88 * need to snap to the edge. | |
| 89 * @private | |
| 90 */ | 83 */ |
| 91 function snapToEdge(point, width, basePoint, baseWidth) { | 84 function invertLayoutType(layoutType) { |
| 92 // If the edge of the region is smaller than this, it will snap to the | 85 switch (layoutType) { |
| 93 // base's edge. | 86 case options.DisplayLayoutType.RIGHT: |
| 94 /** @const */ var SNAP_DISTANCE_PX = 16; | 87 return options.DisplayLayoutType.LEFT; |
| 95 | 88 case options.DisplayLayoutType.LEFT: |
| 96 var startDiff = Math.abs(point - basePoint); | 89 return options.DisplayLayoutType.RIGHT; |
| 97 var endDiff = Math.abs(point + width - (basePoint + baseWidth)); | 90 case options.DisplayLayoutType.TOP: |
| 98 // Prefer the closer one if both edges are close enough. | 91 return options.DisplayLayoutType.BOTTOM; |
| 99 if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) | 92 case options.DisplayLayoutType.BOTTOM: |
| 100 return basePoint; | 93 return options.DisplayLayoutType.TOP; |
| 101 else if (endDiff < SNAP_DISTANCE_PX) | 94 } |
| 102 return basePoint + baseWidth - width; | 95 assertNotReached(); |
| 103 | 96 return layoutType; |
| 104 return point; | |
| 105 } | 97 } |
| 106 | 98 |
| 107 /** | 99 /** |
| 108 * @constructor | 100 * @constructor |
| 109 */ | 101 */ |
| 110 function DisplayLayoutManager() { | 102 function DisplayLayoutManager() { |
| 111 this.displayLayoutMap_ = {}; | 103 this.displayLayoutMap_ = {}; |
| 112 this.displayAreaOffset_ = {x: 0, y: 0}; | 104 this.displayAreaOffset_ = {x: 0, y: 0}; |
| 113 } | 105 } |
| 114 | 106 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 132 visualScale_: 1, | 124 visualScale_: 1, |
| 133 | 125 |
| 134 /** | 126 /** |
| 135 * The offset to the center of the display area div. | 127 * The offset to the center of the display area div. |
| 136 * @type {?options.DisplayPosition} | 128 * @type {?options.DisplayPosition} |
| 137 * @private | 129 * @private |
| 138 */ | 130 */ |
| 139 displayAreaOffset_: null, | 131 displayAreaOffset_: null, |
| 140 | 132 |
| 141 /** | 133 /** |
| 134 * Creates a DisplayLayout object representing the display. |
| 135 * @param {string} id |
| 136 * @param {string} name |
| 137 * @param {options.DisplayBounds} bounds |
| 138 * @param {!options.DisplayLayoutType} layoutType |
| 139 * @param {string} parentId |
| 140 * @return {!options.DisplayLayout} |
| 141 * @private |
| 142 */ |
| 143 createDisplayLayout: function(id, name, bounds, layoutType, parentId) { |
| 144 return { |
| 145 bounds: bounds, |
| 146 div: null, |
| 147 id: id, |
| 148 layoutType: layoutType, |
| 149 name: name, |
| 150 offset: 0, |
| 151 originalDivOffsets: {x: 0, y: 0}, |
| 152 parentId: parentId |
| 153 }; |
| 154 }, |
| 155 |
| 156 /** |
| 142 * Adds a display to the layout map. | 157 * Adds a display to the layout map. |
| 143 * @param {options.DisplayLayout} displayLayout | 158 * @param {options.DisplayLayout} displayLayout |
| 144 */ | 159 */ |
| 145 addDisplayLayout: function(displayLayout) { | 160 addDisplayLayout: function(displayLayout) { |
| 146 this.displayLayoutMap_[displayLayout.id] = displayLayout; | 161 this.displayLayoutMap_[displayLayout.id] = displayLayout; |
| 147 }, | 162 }, |
| 148 | 163 |
| 149 /** | 164 /** |
| 150 * Returns the display layout for |id|. | 165 * Returns the display layout for |id|. |
| 151 * @param {string} id | 166 * @param {string} id |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 * @param {string} id | 244 * @param {string} id |
| 230 * @param {options.DisplayPosition} newPosition | 245 * @param {options.DisplayPosition} newPosition |
| 231 * @private | 246 * @private |
| 232 */ | 247 */ |
| 233 updatePosition: function(id, newPosition) { | 248 updatePosition: function(id, newPosition) { |
| 234 var displayLayout = this.displayLayoutMap_[id]; | 249 var displayLayout = this.displayLayoutMap_[id]; |
| 235 var div = displayLayout.div; | 250 var div = displayLayout.div; |
| 236 var baseLayout = this.getBaseLayout_(displayLayout); | 251 var baseLayout = this.getBaseLayout_(displayLayout); |
| 237 var baseDiv = baseLayout.div; | 252 var baseDiv = baseLayout.div; |
| 238 | 253 |
| 239 newPosition.x = snapToEdge( | 254 newPosition.x = this.snapToEdge_( |
| 240 newPosition.x, div.offsetWidth, baseDiv.offsetLeft, | 255 newPosition.x, div.offsetWidth, baseDiv.offsetLeft, |
| 241 baseDiv.offsetWidth); | 256 baseDiv.offsetWidth); |
| 242 newPosition.y = snapToEdge( | 257 newPosition.y = this.snapToEdge_( |
| 243 newPosition.y, div.offsetHeight, baseDiv.offsetTop, | 258 newPosition.y, div.offsetHeight, baseDiv.offsetTop, |
| 244 baseDiv.offsetHeight); | 259 baseDiv.offsetHeight); |
| 245 | 260 |
| 246 /** @type {!options.DisplayPosition} */ var newCenter = { | 261 /** @type {!options.DisplayPosition} */ var newCenter = { |
| 247 x: newPosition.x + div.offsetWidth / 2, | 262 x: newPosition.x + div.offsetWidth / 2, |
| 248 y: newPosition.y + div.offsetHeight / 2 | 263 y: newPosition.y + div.offsetHeight / 2 |
| 249 }; | 264 }; |
| 250 | 265 |
| 251 /** @type {!options.DisplayBounds} */ var baseBounds = { | 266 /** @type {!options.DisplayBounds} */ var baseBounds = { |
| 252 left: baseDiv.offsetLeft, | 267 left: baseDiv.offsetLeft, |
| 253 top: baseDiv.offsetTop, | 268 top: baseDiv.offsetTop, |
| 254 width: baseDiv.offsetWidth, | 269 width: baseDiv.offsetWidth, |
| 255 height: baseDiv.offsetHeight | 270 height: baseDiv.offsetHeight |
| 256 }; | 271 }; |
| 257 | 272 |
| 258 // This implementation considers only the case of two displays, i.e | 273 // This implementation considers only the case of two displays, i.e |
| 259 // a single parent with one child. | 274 // a single parent with one child. |
| 260 var isPrimary = displayLayout.parentId == ''; | 275 var isPrimary = displayLayout.parentId == ''; |
| 261 | 276 |
| 262 // layoutType is always stored in the child layout. | 277 var layoutType = getLayoutTypeForPosition(baseBounds, newCenter); |
| 263 var layoutType = | 278 if (isPrimary) |
| 264 isPrimary ? baseLayout.layoutType : displayLayout.layoutType; | 279 layoutType = invertLayoutType(layoutType); |
| 265 | |
| 266 switch (getPositionToRectangle(baseBounds, newCenter)) { | |
| 267 case options.DisplayLayoutType.RIGHT: | |
| 268 layoutType = isPrimary ? options.DisplayLayoutType.LEFT : | |
| 269 options.DisplayLayoutType.RIGHT; | |
| 270 break; | |
| 271 case options.DisplayLayoutType.LEFT: | |
| 272 layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : | |
| 273 options.DisplayLayoutType.LEFT; | |
| 274 break; | |
| 275 case options.DisplayLayoutType.TOP: | |
| 276 layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : | |
| 277 options.DisplayLayoutType.TOP; | |
| 278 break; | |
| 279 case options.DisplayLayoutType.BOTTOM: | |
| 280 layoutType = isPrimary ? options.DisplayLayoutType.TOP : | |
| 281 options.DisplayLayoutType.BOTTOM; | |
| 282 break; | |
| 283 } | |
| 284 | 280 |
| 285 if (layoutType == options.DisplayLayoutType.LEFT || | 281 if (layoutType == options.DisplayLayoutType.LEFT || |
| 286 layoutType == options.DisplayLayoutType.RIGHT) { | 282 layoutType == options.DisplayLayoutType.RIGHT) { |
| 287 if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) | 283 if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) { |
| 288 layoutType = isPrimary ? options.DisplayLayoutType.TOP : | 284 layoutType = isPrimary ? options.DisplayLayoutType.TOP : |
| 289 options.DisplayLayoutType.BOTTOM; | 285 options.DisplayLayoutType.BOTTOM; |
| 290 else if (newPosition.y + div.offsetHeight < baseDiv.offsetTop) | 286 } else if (newPosition.y + div.offsetHeight < baseDiv.offsetTop) { |
| 291 layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : | 287 layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM : |
| 292 options.DisplayLayoutType.TOP; | 288 options.DisplayLayoutType.TOP; |
| 289 } |
| 293 } else { | 290 } else { |
| 294 if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth) | 291 if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth) { |
| 295 layoutType = isPrimary ? options.DisplayLayoutType.LEFT : | 292 layoutType = isPrimary ? options.DisplayLayoutType.LEFT : |
| 296 options.DisplayLayoutType.RIGHT; | 293 options.DisplayLayoutType.RIGHT; |
| 297 else if (newPosition.x + div.offsetWidth < baseDiv.offsetLeft) | 294 } else if (newPosition.x + div.offsetWidth < baseDiv.offsetLeft) { |
| 298 layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : | 295 layoutType = isPrimary ? options.DisplayLayoutType.RIGHT : |
| 299 options.DisplayLayoutType.LEFT; | 296 options.DisplayLayoutType.LEFT; |
| 300 } | |
| 301 | |
| 302 var layoutToBase; | |
| 303 if (!isPrimary) { | |
| 304 displayLayout.layoutType = layoutType; | |
| 305 layoutToBase = layoutType; | |
| 306 } else { | |
| 307 baseLayout.layoutType = layoutType; | |
| 308 switch (layoutType) { | |
| 309 case options.DisplayLayoutType.RIGHT: | |
| 310 layoutToBase = options.DisplayLayoutType.LEFT; | |
| 311 break; | |
| 312 case options.DisplayLayoutType.LEFT: | |
| 313 layoutToBase = options.DisplayLayoutType.RIGHT; | |
| 314 break; | |
| 315 case options.DisplayLayoutType.TOP: | |
| 316 layoutToBase = options.DisplayLayoutType.BOTTOM; | |
| 317 break; | |
| 318 case options.DisplayLayoutType.BOTTOM: | |
| 319 layoutToBase = options.DisplayLayoutType.TOP; | |
| 320 break; | |
| 321 } | 297 } |
| 322 } | 298 } |
| 323 | 299 |
| 324 switch (layoutToBase) { | 300 // layoutType is always stored in the child layout. |
| 325 case options.DisplayLayoutType.RIGHT: | 301 if (isPrimary) |
| 326 div.style.left = baseDiv.offsetLeft + baseDiv.offsetWidth + 'px'; | 302 baseLayout.layoutType = layoutType; |
| 327 div.style.top = newPosition.y + 'px'; | 303 else |
| 328 break; | 304 displayLayout.layoutType = layoutType; |
| 329 case options.DisplayLayoutType.LEFT: | 305 |
| 330 div.style.left = baseDiv.offsetLeft - div.offsetWidth + 'px'; | 306 var layoutToBase = isPrimary ? invertLayoutType(layoutType) : layoutType; |
| 331 div.style.top = newPosition.y + 'px'; | 307 |
| 332 break; | 308 this.setDivPosition_(div, newPosition, baseDiv, layoutToBase); |
| 333 case options.DisplayLayoutType.TOP: | |
| 334 div.style.top = baseDiv.offsetTop - div.offsetHeight + 'px'; | |
| 335 div.style.left = newPosition.x + 'px'; | |
| 336 break; | |
| 337 case options.DisplayLayoutType.BOTTOM: | |
| 338 div.style.top = baseDiv.offsetTop + baseDiv.offsetHeight + 'px'; | |
| 339 div.style.left = newPosition.x + 'px'; | |
| 340 break; | |
| 341 } | |
| 342 }, | 309 }, |
| 343 | 310 |
| 344 /** | 311 /** |
| 345 * Called from the UI to finalize the location of display |id| after updates | 312 * Called from the UI to finalize the location of display |id| after updates |
| 346 * are complete (e.g. after a drag was completed). | 313 * are complete (e.g. after a drag was completed). |
| 347 * @param {string} id | 314 * @param {string} id |
| 348 * @return {boolean} True if the final position differs from the original. | 315 * @return {boolean} True if the final position differs from the original. |
| 349 */ | 316 */ |
| 350 finalizePosition: function(id) { | 317 finalizePosition: function(id) { |
| 351 // Make sure the dragging location is connected. | |
| 352 var displayLayout = this.displayLayoutMap_[id]; | 318 var displayLayout = this.displayLayoutMap_[id]; |
| 353 var div = displayLayout.div; | 319 var div = displayLayout.div; |
| 354 var baseLayout = this.getBaseLayout_(displayLayout); | 320 var baseLayout = this.getBaseLayout_(displayLayout); |
| 355 var baseDiv = baseLayout.div; | |
| 356 | 321 |
| 357 var isPrimary = displayLayout.parentId == ''; | 322 var isPrimary = displayLayout.parentId == ''; |
| 358 var layoutType = | 323 var layoutType = |
| 359 isPrimary ? baseLayout.layoutType : displayLayout.layoutType; | 324 isPrimary ? baseLayout.layoutType : displayLayout.layoutType; |
| 360 | 325 |
| 361 // The number of pixels to share the edges between displays. | 326 // Make sure the dragging location is connected. |
| 362 /** @const */ var MIN_OFFSET_OVERLAP = 5; | 327 this.adjustCorners_(div, baseLayout.div, layoutType); |
| 363 | |
| 364 if (layoutType == options.DisplayLayoutType.LEFT || | |
| 365 layoutType == options.DisplayLayoutType.RIGHT) { | |
| 366 var top = Math.max( | |
| 367 div.offsetTop, | |
| 368 baseDiv.offsetTop - div.offsetHeight + MIN_OFFSET_OVERLAP); | |
| 369 top = Math.min( | |
| 370 top, baseDiv.offsetTop + baseDiv.offsetHeight - MIN_OFFSET_OVERLAP); | |
| 371 div.style.top = top + 'px'; | |
| 372 } else { | |
| 373 var left = Math.max( | |
| 374 div.offsetLeft, | |
| 375 baseDiv.offsetLeft - div.offsetWidth + MIN_OFFSET_OVERLAP); | |
| 376 left = Math.min( | |
| 377 left, | |
| 378 baseDiv.offsetLeft + baseDiv.offsetWidth - MIN_OFFSET_OVERLAP); | |
| 379 div.style.left = left + 'px'; | |
| 380 } | |
| 381 | 328 |
| 382 // Calculate the offset of the child display. | 329 // Calculate the offset of the child display. |
| 383 this.calculateOffset_(isPrimary ? baseLayout : displayLayout); | 330 this.calculateOffset_(isPrimary ? baseLayout : displayLayout); |
| 384 | 331 |
| 385 return displayLayout.originalPosition.x != div.offsetLeft || | 332 return displayLayout.originalDivOffsets.x != div.offsetLeft || |
| 386 displayLayout.originalPosition.y != div.offsetTop; | 333 displayLayout.originalDivOffsets.y != div.offsetTop; |
| 387 }, | 334 }, |
| 388 | 335 |
| 389 /** | 336 /** |
| 390 * Calculates the display area offset and scale. | 337 * Calculates the display area offset and scale. |
| 391 * @param {!Element} displayAreaDiv The containing display area div. | 338 * @param {!Element} displayAreaDiv The containing display area div. |
| 392 * @param {number} minVisualScale The minimum visualScale value. | 339 * @param {number} minVisualScale The minimum visualScale value. |
| 393 */ | 340 */ |
| 394 calculateDisplayArea_(displayAreaDiv, minVisualScale) { | 341 calculateDisplayArea_(displayAreaDiv, minVisualScale) { |
| 395 var maxWidth = 0; | 342 var maxWidth = 0; |
| 396 var maxHeight = 0; | 343 var maxHeight = 0; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 | 382 |
| 436 /** | 383 /** |
| 437 * Creates a div element and assigns it to |displayLayout|. Returns the | 384 * Creates a div element and assigns it to |displayLayout|. Returns the |
| 438 * created div for additional decoration. | 385 * created div for additional decoration. |
| 439 * @param {string} id | 386 * @param {string} id |
| 440 * @param {!Element} displayAreaDiv The containing display area div. | 387 * @param {!Element} displayAreaDiv The containing display area div. |
| 441 */ | 388 */ |
| 442 createDisplayLayoutDiv_: function(id, displayAreaDiv) { | 389 createDisplayLayoutDiv_: function(id, displayAreaDiv) { |
| 443 var displayLayout = this.displayLayoutMap_[id]; | 390 var displayLayout = this.displayLayoutMap_[id]; |
| 444 var parentId = displayLayout.parentId; | 391 var parentId = displayLayout.parentId; |
| 445 var offset = this.displayAreaOffset_; | |
| 446 if (parentId) { | 392 if (parentId) { |
| 447 // Ensure the parent div is created first. | 393 // Ensure the parent div is created first. |
| 448 var parentLayout = this.displayLayoutMap_[parentId]; | 394 var parentLayout = this.displayLayoutMap_[parentId]; |
| 449 if (!parentLayout.div) | 395 if (!parentLayout.div) |
| 450 this.createDisplayLayoutDiv_(parentId, displayAreaDiv); | 396 this.createDisplayLayoutDiv_(parentId, displayAreaDiv); |
| 451 } | 397 } |
| 452 | 398 |
| 453 var div = /** @type {!HTMLElement} */ (document.createElement('div')); | 399 var div = /** @type {!HTMLElement} */ (document.createElement('div')); |
| 454 div.className = 'displays-display'; | 400 div.className = 'displays-display'; |
| 401 displayLayout.div = div; |
| 455 | 402 |
| 456 // div needs to be added to the DOM tree first, otherwise offsetHeight for | 403 // div needs to be added to the DOM tree first, otherwise offsetHeight for |
| 457 // nameContainer below cannot be computed. | 404 // nameContainer below cannot be computed. |
| 458 displayAreaDiv.appendChild(div); | 405 displayAreaDiv.appendChild(div); |
| 459 | 406 |
| 460 var nameContainer = document.createElement('div'); | 407 var nameContainer = document.createElement('div'); |
| 461 nameContainer.textContent = displayLayout.name; | 408 nameContainer.textContent = displayLayout.name; |
| 462 div.appendChild(nameContainer); | 409 div.appendChild(nameContainer); |
| 463 | 410 |
| 464 var bounds = displayLayout.bounds; | 411 var newHeight = |
| 465 div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; | 412 Math.floor(displayLayout.bounds.height * this.visualScale_); |
| 466 var newHeight = Math.floor(bounds.height * this.visualScale_); | |
| 467 div.style.height = newHeight + 'px'; | |
| 468 nameContainer.style.marginTop = | 413 nameContainer.style.marginTop = |
| 469 (newHeight - nameContainer.offsetHeight) / 2 + 'px'; | 414 (newHeight - nameContainer.offsetHeight) / 2 + 'px'; |
| 470 | 415 |
| 416 this.layoutDivFromBounds_(displayLayout); |
| 417 |
| 418 displayLayout.originalDivOffsets.x = div.offsetLeft; |
| 419 displayLayout.originalDivOffsets.y = div.offsetTop; |
| 420 |
| 421 this.calculateOffset_(displayLayout); |
| 422 }, |
| 423 |
| 424 /** |
| 425 * Calculates the div layout for displayLayout. |
| 426 * @param {options.DisplayLayout} displayLayout |
| 427 */ |
| 428 layoutDivFromBounds_: function(displayLayout) { |
| 429 var div = displayLayout.div; |
| 430 var bounds = displayLayout.bounds; |
| 431 |
| 432 div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; |
| 433 div.style.height = Math.floor(bounds.height * this.visualScale_) + 'px'; |
| 434 |
| 435 var offset = this.displayAreaOffset_; |
| 471 if (displayLayout.parentId == '') { | 436 if (displayLayout.parentId == '') { |
| 472 div.style.left = | 437 div.style.left = |
| 473 Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; | 438 Math.floor(bounds.left * this.visualScale_) + offset.x + 'px'; |
| 474 div.style.top = | 439 div.style.top = |
| 475 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; | 440 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| 476 } else { | 441 } else { |
| 477 // Don't trust the child display's x or y, because it may cause a | 442 // Don't trust the child display's x or y, because it may cause a |
| 478 // 1px gap due to rounding, which will create a fake update on end | 443 // 1px gap due to rounding, which will create a fake update on end |
| 479 // dragging. See crbug.com/386401 | 444 // dragging. See crbug.com/386401 |
| 480 var parentDiv = this.displayLayoutMap_[displayLayout.parentId].div; | 445 var parentDiv = this.displayLayoutMap_[displayLayout.parentId].div; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 496 div.style.top = parentDiv.offsetTop + parentDiv.offsetHeight + 'px'; | 461 div.style.top = parentDiv.offsetTop + parentDiv.offsetHeight + 'px'; |
| 497 break; | 462 break; |
| 498 case options.DisplayLayoutType.LEFT: | 463 case options.DisplayLayoutType.LEFT: |
| 499 div.style.left = parentDiv.offsetLeft - div.offsetWidth + 'px'; | 464 div.style.left = parentDiv.offsetLeft - div.offsetWidth + 'px'; |
| 500 div.style.top = | 465 div.style.top = |
| 501 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; | 466 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px'; |
| 502 break; | 467 break; |
| 503 } | 468 } |
| 504 } | 469 } |
| 505 | 470 |
| 506 displayLayout.div = div; | |
| 507 displayLayout.originalPosition.x = div.offsetLeft; | |
| 508 displayLayout.originalPosition.y = div.offsetTop; | |
| 509 | |
| 510 this.calculateOffset_(displayLayout); | |
| 511 }, | 471 }, |
| 512 | 472 |
| 513 /** | 473 /** |
| 514 * Calculates the offset for display |id| relative to its parent. | 474 * Calculates the offset for displayLayout relative to its parent. |
| 515 * @param {options.DisplayLayout} displayLayout | 475 * @param {options.DisplayLayout} displayLayout |
| 516 */ | 476 */ |
| 517 calculateOffset_: function(displayLayout) { | 477 calculateOffset_: function(displayLayout) { |
| 518 // Offset is calculated from top or left edge. | 478 // Offset is calculated from top or left edge. |
| 519 var parent = this.displayLayoutMap_[displayLayout.parentId]; | 479 var parent = this.displayLayoutMap_[displayLayout.parentId]; |
| 520 if (!parent) { | 480 if (!parent) { |
| 521 displayLayout.offset = 0; | 481 displayLayout.offset = 0; |
| 522 return; | 482 return; |
| 523 } | 483 } |
| 524 var offset; | 484 var offset; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 541 getBaseLayout_(displayLayout) { | 501 getBaseLayout_(displayLayout) { |
| 542 if (displayLayout.parentId != '') | 502 if (displayLayout.parentId != '') |
| 543 return this.displayLayoutMap_[displayLayout.parentId]; | 503 return this.displayLayoutMap_[displayLayout.parentId]; |
| 544 for (var childId in this.displayLayoutMap_) { | 504 for (var childId in this.displayLayoutMap_) { |
| 545 var child = this.displayLayoutMap_[childId]; | 505 var child = this.displayLayoutMap_[childId]; |
| 546 if (child.parentId == displayLayout.id) | 506 if (child.parentId == displayLayout.id) |
| 547 return child; | 507 return child; |
| 548 } | 508 } |
| 549 assertNotReached(); | 509 assertNotReached(); |
| 550 return null; | 510 return null; |
| 511 }, |
| 512 |
| 513 /** |
| 514 * Update the location |div| to the position closest to |newPosition| along |
| 515 * the edge of |parentDiv| specified by |layoutType|. |
| 516 * @param {?HTMLElement} div |
| 517 * @param {options.DisplayPosition} newPosition |
| 518 * @param {?HTMLElement} parentDiv |
| 519 * @param {!options.DisplayLayoutType} layoutType |
| 520 * @private |
| 521 */ |
| 522 setDivPosition_(div, newPosition, parentDiv, layoutType) { |
| 523 switch (layoutType) { |
| 524 case options.DisplayLayoutType.RIGHT: |
| 525 div.style.left = parentDiv.offsetLeft + parentDiv.offsetWidth + 'px'; |
| 526 div.style.top = newPosition.y + 'px'; |
| 527 break; |
| 528 case options.DisplayLayoutType.LEFT: |
| 529 div.style.left = parentDiv.offsetLeft - div.offsetWidth + 'px'; |
| 530 div.style.top = newPosition.y + 'px'; |
| 531 break; |
| 532 case options.DisplayLayoutType.TOP: |
| 533 div.style.top = parentDiv.offsetTop - div.offsetHeight + 'px'; |
| 534 div.style.left = newPosition.x + 'px'; |
| 535 break; |
| 536 case options.DisplayLayoutType.BOTTOM: |
| 537 div.style.top = parentDiv.offsetTop + parentDiv.offsetHeight + 'px'; |
| 538 div.style.left = newPosition.x + 'px'; |
| 539 break; |
| 540 } |
| 541 }, |
| 542 |
| 543 /** |
| 544 * Snaps the region [point, width] to [basePoint, baseWidth] if |
| 545 * the [point, width] is close enough to the base's edge. |
| 546 * @param {number} point The starting point of the region. |
| 547 * @param {number} width The width of the region. |
| 548 * @param {number} basePoint The starting point of the base region. |
| 549 * @param {number} baseWidth The width of the base region. |
| 550 * @param {number} opt_snapDistance Provide to override the snap distance. |
| 551 * 0 means snap at any distance. |
| 552 * @return {number} The moved point. Returns the point itself if it doesn't |
| 553 * need to snap to the edge. |
| 554 * @private |
| 555 */ |
| 556 snapToEdge_: function( |
| 557 point, width, basePoint, baseWidth, opt_snapDistance) { |
| 558 // If the edge of the region is smaller than this, it will snap to the |
| 559 // base's edge. |
| 560 /** @const */ var SNAP_DISTANCE_PX = 16; |
| 561 var snapDist; |
| 562 if (opt_snapDistance !== undefined) |
| 563 snapDist = opt_snapDistance; |
| 564 else |
| 565 snapDist = SNAP_DISTANCE_PX; |
| 566 var startDiff = Math.abs(point - basePoint); |
| 567 var endDiff = Math.abs(point + width - (basePoint + baseWidth)); |
| 568 // Prefer the closer one if both edges are close enough. |
| 569 if ((!snapDist || startDiff < snapDist) && startDiff < endDiff) |
| 570 return basePoint; |
| 571 else if (!snapDist || endDiff < SNAP_DISTANCE_PX) |
| 572 return basePoint + baseWidth - width; |
| 573 |
| 574 return point; |
| 575 }, |
| 576 |
| 577 /** |
| 578 * Ensures that there is a minimum overlap when displays meet at a corner. |
| 579 * @param {?HTMLElement} div |
| 580 * @param {?HTMLElement} parentDiv |
| 581 * @param {options.DisplayLayoutType} layoutType |
| 582 * @private |
| 583 */ |
| 584 adjustCorners_: function(div, parentDiv, layoutType) { |
| 585 // The number of pixels to share the edges between displays. |
| 586 /** @const */ var MIN_OFFSET_OVERLAP = 5; |
| 587 |
| 588 if (layoutType == options.DisplayLayoutType.LEFT || |
| 589 layoutType == options.DisplayLayoutType.RIGHT) { |
| 590 var top = Math.max( |
| 591 div.offsetTop, |
| 592 parentDiv.offsetTop - div.offsetHeight + MIN_OFFSET_OVERLAP); |
| 593 top = Math.min( |
| 594 top, |
| 595 parentDiv.offsetTop + parentDiv.offsetHeight - MIN_OFFSET_OVERLAP); |
| 596 div.style.top = top + 'px'; |
| 597 } else { |
| 598 var left = Math.max( |
| 599 div.offsetLeft, |
| 600 parentDiv.offsetLeft - div.offsetWidth + MIN_OFFSET_OVERLAP); |
| 601 left = Math.min( |
| 602 left, |
| 603 parentDiv.offsetLeft + parentDiv.offsetWidth - MIN_OFFSET_OVERLAP); |
| 604 div.style.left = left + 'px'; |
| 605 } |
| 551 } | 606 } |
| 552 }; | 607 }; |
| 553 | 608 |
| 554 // Export | 609 // Export |
| 555 return {DisplayLayoutManager: DisplayLayoutManager}; | 610 return {DisplayLayoutManager: DisplayLayoutManager}; |
| 556 }); | 611 }); |
| OLD | NEW |