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 |