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

Side by Side Diff: chrome/browser/resources/options/chromeos/display_layout_manager.js

Issue 1649173002: Add DisplayLayoutManagerMulti (WIP) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@issue_576375_display3e
Patch Set: Rebase Created 4 years, 10 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 unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698