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

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

Issue 1626573003: Extract DisplayLayoutManager from display_options.js (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase off 1633983002 + fixes Created 4 years, 11 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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
9 * ash::DisplayController.
10 * @enum {number}
11 */
12 options.DisplayLayoutType = {
13 TOP: 0,
14 RIGHT: 1,
15 BOTTOM: 2,
16 LEFT: 3
17 };
18
19 /**
20 * Enumeration of multi display mode. These values must match the C++ values in 8 * Enumeration of multi display mode. These values must match the C++ values in
21 * ash::DisplayManager. 9 * ash::DisplayManager.
22 * @enum {number} 10 * @enum {number}
23 */ 11 */
24 options.MultiDisplayMode = { 12 options.MultiDisplayMode = {
25 EXTENDED: 0, 13 EXTENDED: 0,
26 MIRRORING: 1, 14 MIRRORING: 1,
27 UNIFIED: 2, 15 UNIFIED: 2,
28 }; 16 };
29 17
30 /** 18 /**
31 * @typedef {{ 19 * @typedef {{
32 * left: number,
33 * top: number,
34 * width: number,
35 * height: number
36 * }}
37 */
38 options.DisplayBounds;
39
40 /**
41 * @typedef {{
42 * x: number,
43 * y: number
44 * }}
45 */
46 options.DisplayPosition;
47
48 /**
49 * @typedef {{
50 * width: number, 20 * width: number,
51 * height: number, 21 * height: number,
52 * originalWidth: number, 22 * originalWidth: number,
53 * originalHeight: number, 23 * originalHeight: number,
54 * deviceScaleFactor: number, 24 * deviceScaleFactor: number,
55 * scale: number, 25 * scale: number,
56 * refreshRate: number, 26 * refreshRate: number,
57 * isBest: boolean, 27 * isBest: boolean,
58 * selected: boolean 28 * selected: boolean
59 * }} 29 * }}
(...skipping 16 matching lines...) Expand all
76 * id: string, 46 * id: string,
77 * isInternal: boolean, 47 * isInternal: boolean,
78 * isPrimary: boolean, 48 * isPrimary: boolean,
79 * resolutions: !Array<!options.DisplayMode>, 49 * resolutions: !Array<!options.DisplayMode>,
80 * name: string, 50 * name: string,
81 * rotation: number 51 * rotation: number
82 * }} 52 * }}
83 */ 53 */
84 options.DisplayInfo; 54 options.DisplayInfo;
85 55
86 /**
87 * @typedef {{
88 * bounds: !options.DisplayBounds,
89 * div: ?HTMLElement,
90 * id: string,
91 * isPrimary: boolean,
92 * layoutType: options.DisplayLayoutType,
93 * name: string,
94 * originalPosition: !options.DisplayPosition
95 * }}
96 */
97 options.DisplayLayout;
98
99 cr.define('options', function() { 56 cr.define('options', function() {
100 var Page = cr.ui.pageManager.Page; 57 var Page = cr.ui.pageManager.Page;
101 var PageManager = cr.ui.pageManager.PageManager; 58 var PageManager = cr.ui.pageManager.PageManager;
102 59
103 // The scale ratio of the display rectangle to its original size. 60 // The scale ratio of the display rectangle to its original size.
104 /** @const */ var VISUAL_SCALE = 1 / 10; 61 /** @const */ var VISUAL_SCALE = 1 / 10;
105 62
106 // The number of pixels to share the edges between displays.
107 /** @const */ var MIN_OFFSET_OVERLAP = 5;
108
109 /**
110 * Gets the layout type of |point| relative to |rect|.
111 * @param {!options.DisplayBounds} rect The base rectangle.
112 * @param {!options.DisplayPosition} point The point to check the position.
113 * @return {options.DisplayLayoutType} The position of the calculated point.
114 */
115 function getPositionToRectangle(rect, point) {
116 // Separates the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of
117 // the rect, and decides which area the display should reside.
118 var diagonalSlope = rect.height / rect.width;
119 var topDownIntercept = rect.top - rect.left * diagonalSlope;
120 var bottomUpIntercept = rect.top + rect.height + rect.left * diagonalSlope;
121
122 if (point.y > topDownIntercept + point.x * diagonalSlope) {
123 if (point.y > bottomUpIntercept - point.x * diagonalSlope)
124 return options.DisplayLayoutType.BOTTOM;
125 else
126 return options.DisplayLayoutType.LEFT;
127 } else {
128 if (point.y > bottomUpIntercept - point.x * diagonalSlope)
129 return options.DisplayLayoutType.RIGHT;
130 else
131 return options.DisplayLayoutType.TOP;
132 }
133 }
134
135 /** 63 /**
136 * Snaps the region [point, width] to [basePoint, baseWidth] if 64 * Snaps the region [point, width] to [basePoint, baseWidth] if
137 * the [point, width] is close enough to the base's edge. 65 * the [point, width] is close enough to the base's edge.
138 * @param {number} point The starting point of the region. 66 * @param {number} point The starting point of the region.
139 * @param {number} width The width of the region. 67 * @param {number} width The width of the region.
140 * @param {number} basePoint The starting point of the base region. 68 * @param {number} basePoint The starting point of the base region.
141 * @param {number} baseWidth The width of the base region. 69 * @param {number} baseWidth The width of the base region.
142 * @return {number} The moved point. Returns the point itself if it doesn't 70 * @return {number} The moved point. Returns the point itself if it doesn't
143 * need to snap to the edge. 71 * need to snap to the edge.
144 * @private 72 * @private
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 126
199 /** 127 /**
200 * The array of current output displays. It also contains the display 128 * The array of current output displays. It also contains the display
201 * rectangles currently rendered on screen. 129 * rectangles currently rendered on screen.
202 * @type {!Array<!options.DisplayInfo>} 130 * @type {!Array<!options.DisplayInfo>}
203 * @private 131 * @private
204 */ 132 */
205 displays_: [], 133 displays_: [],
206 134
207 /** 135 /**
208 * An object containing DisplayLayout objects for each entry in |displays_|. 136 * Manages the display layout.
209 * @type {!Object<!options.DisplayLayout>} 137 * @type {?options.DisplayLayoutManager}
210 * @private 138 * @private
211 */ 139 */
212 displayLayoutMap_: {}, 140 displayLayoutManager_: null,
213 141
214 /** 142 /**
215 * The id of the currently focused display, or empty for none. 143 * The id of the currently focused display, or empty for none.
216 * @type {string} 144 * @type {string}
217 * @private 145 * @private
218 */ 146 */
219 focusedId_: '', 147 focusedId_: '',
220 148
221 /** 149 /**
222 * The primary display id.
223 * @type {string}
224 * @private
225 */
226 primaryDisplayId_: '',
227
228 /**
229 * The secondary display id.
230 * @type {string}
231 * @private
232 */
233 secondaryDisplayId_: '',
234
235 /**
236 * Drag info. 150 * Drag info.
237 * @type {?{displayId: string, 151 * @type {?{displayId: string,
238 * originalLocation: !options.DisplayPosition, 152 * originalLocation: !options.DisplayPosition,
239 * eventLocation: !options.DisplayPosition}} 153 * eventLocation: !options.DisplayPosition}}
240 * @private 154 * @private
241 */ 155 */
242 dragInfo_: null, 156 dragInfo_: null,
243 157
244 /** 158 /**
245 * The container div element which contains all of the display rectangles. 159 * The container div element which contains all of the display rectangles.
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 * @param {string} id 346 * @param {string} id
433 * @return {options.DisplayInfo} 347 * @return {options.DisplayInfo}
434 */ 348 */
435 getDisplayInfoFromId(id) { 349 getDisplayInfoFromId(id) {
436 return this.displays_.find(function(display) { 350 return this.displays_.find(function(display) {
437 return display.id == id; 351 return display.id == id;
438 }); 352 });
439 }, 353 },
440 354
441 /** 355 /**
442 * Collects the current data and sends it to Chrome. 356 * Sends the display layout for the secondary display to Chrome.
443 * @private 357 * @private
444 */ 358 */
445 sendDragResult_: function() { 359 sendDragResult_: function() {
446 // Offset is calculated from top or left edge. 360 // The first non-primary display is the secondary display.
447 var primary = this.displayLayoutMap_[this.primaryDisplayId_]; 361 var secondaryId;
448 var secondary = this.displayLayoutMap_[this.secondaryDisplayId_]; 362 for (var i = 0; i < this.displays_.length; i++) {
449 var layoutType = secondary.layoutType; 363 if (!this.displays_[i].isPrimary) {
450 var offset; 364 secondaryId = this.displays_[i].id;
451 if (layoutType == options.DisplayLayoutType.LEFT || 365 break;
452 layoutType == options.DisplayLayoutType.RIGHT) { 366 }
453 offset = secondary.div.offsetTop - primary.div.offsetTop;
454 } else {
455 offset = secondary.div.offsetLeft - primary.div.offsetLeft;
456 } 367 }
457 offset = Math.floor(offset / this.visualScale_); 368 assert(!!secondaryId);
458 chrome.send('setDisplayLayout', [secondary.id, layoutType, offset]); 369 var displayLayout =
370 this.displayLayoutManager_.getDisplayLayout(secondaryId);
371 chrome.send(
372 'setDisplayLayout',
373 [secondaryId, displayLayout.layoutType, displayLayout.offset]);
459 }, 374 },
460 375
461 /** 376 /**
462 * Processes the actual dragging of display rectangle. 377 * Processes the actual dragging of display rectangle.
463 * @param {Event} e The event which triggers this drag. 378 * @param {Event} e The event which triggers this drag.
464 * @param {options.DisplayPosition} eventLocation The location where the 379 * @param {options.DisplayPosition} eventLocation The location where the
465 * event happens. 380 * event happens.
466 * @private 381 * @private
467 */ 382 */
468 processDragging_: function(e, eventLocation) { 383 processDragging_: function(e, eventLocation) {
469 if (!this.dragInfo_) 384 if (!this.dragInfo_)
470 return true; 385 return true;
471 386
472 e.preventDefault(); 387 e.preventDefault();
473 388
474 // Note that current code of moving display-rectangles doesn't work
475 // if there are >=3 displays. This is our assumption for M21.
476 // TODO(mukai): Fix the code to allow >=3 displays.
477 var dragInfo = this.dragInfo_; 389 var dragInfo = this.dragInfo_;
390
478 /** @type {options.DisplayPosition} */ var newPosition = { 391 /** @type {options.DisplayPosition} */ var newPosition = {
479 x: dragInfo.originalLocation.x + 392 x: dragInfo.originalLocation.x +
480 (eventLocation.x - dragInfo.eventLocation.x), 393 (eventLocation.x - dragInfo.eventLocation.x),
481 y: dragInfo.originalLocation.y + 394 y: dragInfo.originalLocation.y +
482 (eventLocation.y - dragInfo.eventLocation.y) 395 (eventLocation.y - dragInfo.eventLocation.y)
483 }; 396 };
484 397
485 var dragLayout = this.displayLayoutMap_[dragInfo.displayId]; 398 this.displayLayoutManager_.updatePosition(
486 var draggingDiv = dragLayout.div; 399 this.dragInfo_.displayId, newPosition);
487
488 var baseDisplayId = dragLayout.isPrimary ? this.secondaryDisplayId_ :
489 this.primaryDisplayId_;
490 var baseLayout = this.displayLayoutMap_[baseDisplayId];
491 var baseDiv = baseLayout.div;
492
493 newPosition.x = snapToEdge(
494 newPosition.x, draggingDiv.offsetWidth, baseDiv.offsetLeft,
495 baseDiv.offsetWidth);
496 newPosition.y = snapToEdge(
497 newPosition.y, draggingDiv.offsetHeight, baseDiv.offsetTop,
498 baseDiv.offsetHeight);
499
500 /** @type {!options.DisplayPosition} */ var newCenter = {
501 x: newPosition.x + draggingDiv.offsetWidth / 2,
502 y: newPosition.y + draggingDiv.offsetHeight / 2
503 };
504
505 /** @type {!options.DisplayBounds} */ var baseBounds = {
506 left: baseDiv.offsetLeft,
507 top: baseDiv.offsetTop,
508 width: baseDiv.offsetWidth,
509 height: baseDiv.offsetHeight
510 };
511
512 var isPrimary = dragLayout.isPrimary;
513 // layoutType is always stored in the secondary layout.
514 var layoutType =
515 isPrimary ? baseLayout.layoutType : dragLayout.layoutType;
516
517 switch (getPositionToRectangle(baseBounds, newCenter)) {
518 case options.DisplayLayoutType.RIGHT:
519 layoutType = isPrimary ? options.DisplayLayoutType.LEFT :
520 options.DisplayLayoutType.RIGHT;
521 break;
522 case options.DisplayLayoutType.LEFT:
523 layoutType = isPrimary ? options.DisplayLayoutType.RIGHT :
524 options.DisplayLayoutType.LEFT;
525 break;
526 case options.DisplayLayoutType.TOP:
527 layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM :
528 options.DisplayLayoutType.TOP;
529 break;
530 case options.DisplayLayoutType.BOTTOM:
531 layoutType = isPrimary ? options.DisplayLayoutType.TOP :
532 options.DisplayLayoutType.BOTTOM;
533 break;
534 }
535
536 if (layoutType == options.DisplayLayoutType.LEFT ||
537 layoutType == options.DisplayLayoutType.RIGHT) {
538 if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight)
539 layoutType = isPrimary ? options.DisplayLayoutType.TOP :
540 options.DisplayLayoutType.BOTTOM;
541 else if (newPosition.y + draggingDiv.offsetHeight < baseDiv.offsetTop)
542 layoutType = isPrimary ? options.DisplayLayoutType.BOTTOM :
543 options.DisplayLayoutType.TOP;
544 } else {
545 if (newPosition.x > baseDiv.offsetLeft + baseDiv.offsetWidth)
546 layoutType = isPrimary ? options.DisplayLayoutType.LEFT :
547 options.DisplayLayoutType.RIGHT;
548 else if (newPosition.x + draggingDiv.offsetWidth < baseDiv.offsetLeft)
549 layoutType = isPrimary ? options.DisplayLayoutType.RIGHT :
550 options.DisplayLayoutType.LEFT;
551 }
552
553 var layoutToBase;
554 if (!isPrimary) {
555 dragLayout.layoutType = layoutType;
556 layoutToBase = layoutType;
557 } else {
558 baseLayout.layoutType = layoutType;
559 switch (layoutType) {
560 case options.DisplayLayoutType.RIGHT:
561 layoutToBase = options.DisplayLayoutType.LEFT;
562 break;
563 case options.DisplayLayoutType.LEFT:
564 layoutToBase = options.DisplayLayoutType.RIGHT;
565 break;
566 case options.DisplayLayoutType.TOP:
567 layoutToBase = options.DisplayLayoutType.BOTTOM;
568 break;
569 case options.DisplayLayoutType.BOTTOM:
570 layoutToBase = options.DisplayLayoutType.TOP;
571 break;
572 }
573 }
574
575 switch (layoutToBase) {
576 case options.DisplayLayoutType.RIGHT:
577 draggingDiv.style.left =
578 baseDiv.offsetLeft + baseDiv.offsetWidth + 'px';
579 draggingDiv.style.top = newPosition.y + 'px';
580 break;
581 case options.DisplayLayoutType.LEFT:
582 draggingDiv.style.left =
583 baseDiv.offsetLeft - draggingDiv.offsetWidth + 'px';
584 draggingDiv.style.top = newPosition.y + 'px';
585 break;
586 case options.DisplayLayoutType.TOP:
587 draggingDiv.style.top =
588 baseDiv.offsetTop - draggingDiv.offsetHeight + 'px';
589 draggingDiv.style.left = newPosition.x + 'px';
590 break;
591 case options.DisplayLayoutType.BOTTOM:
592 draggingDiv.style.top =
593 baseDiv.offsetTop + baseDiv.offsetHeight + 'px';
594 draggingDiv.style.left = newPosition.x + 'px';
595 break;
596 }
597 400
598 return false; 401 return false;
599 }, 402 },
600 403
601 /** 404 /**
602 * Start dragging of a display rectangle. 405 * Start dragging of a display rectangle.
603 * @param {!HTMLElement} target The event target. 406 * @param {!HTMLElement} target The event target.
604 * @param {!options.DisplayPosition} eventLocation The event location. 407 * @param {!options.DisplayPosition} eventLocation The event location.
605 * @private 408 * @private
606 */ 409 */
607 startDragging_: function(target, eventLocation) { 410 startDragging_: function(target, eventLocation) {
608 var oldFocusedId = this.focusedId_; 411 var oldFocusedId = this.focusedId_;
609 var newFocusedId; 412 var newFocusedId;
610 var willUpdateDisplayDescription = false; 413 var willUpdateDisplayDescription = false;
611 for (var i = 0; i < this.displays_.length; i++) { 414 for (var i = 0; i < this.displays_.length; i++) {
612 var displayLayout = this.displayLayoutMap_[this.displays_[i].id]; 415 var displayLayout =
416 this.displayLayoutManager_.getDisplayLayout(this.displays_[i].id);
613 if (displayLayout.div == target || 417 if (displayLayout.div == target ||
614 (target.offsetParent && target.offsetParent == displayLayout.div)) { 418 (target.offsetParent && target.offsetParent == displayLayout.div)) {
615 newFocusedId = displayLayout.id; 419 newFocusedId = displayLayout.id;
616 break; 420 break;
617 } 421 }
618 } 422 }
619 if (!newFocusedId) 423 if (!newFocusedId)
620 return false; 424 return false;
621 425
622 this.focusedId_ = newFocusedId; 426 this.focusedId_ = newFocusedId;
623 willUpdateDisplayDescription = newFocusedId != oldFocusedId; 427 willUpdateDisplayDescription = newFocusedId != oldFocusedId;
624 428
625 for (var i = 0; i < this.displays_.length; i++) { 429 for (var i = 0; i < this.displays_.length; i++) {
626 var displayLayout = this.displayLayoutMap_[this.displays_[i].id]; 430 var displayLayout =
431 this.displayLayoutManager_.getDisplayLayout(this.displays_[i].id);
627 displayLayout.div.className = 'displays-display'; 432 displayLayout.div.className = 'displays-display';
628 if (displayLayout.id != this.focusedId_) 433 if (displayLayout.id != this.focusedId_)
629 continue; 434 continue;
630 435
631 displayLayout.div.classList.add('displays-focused'); 436 displayLayout.div.classList.add('displays-focused');
632 if (this.displays_.length > 1) { 437 if (this.displays_.length > 1) {
633 this.dragInfo_ = { 438 this.dragInfo_ = {
634 displayId: displayLayout.id, 439 displayId: displayLayout.id,
635 originalLocation: { 440 originalLocation: {
636 x: displayLayout.div.offsetLeft, 441 x: displayLayout.div.offsetLeft,
(...skipping 12 matching lines...) Expand all
649 /** 454 /**
650 * finish the current dragging of displays. 455 * finish the current dragging of displays.
651 * @param {Event} e The event which triggers this. 456 * @param {Event} e The event which triggers this.
652 * @private 457 * @private
653 */ 458 */
654 endDragging_: function(e) { 459 endDragging_: function(e) {
655 this.lastTouchLocation_ = null; 460 this.lastTouchLocation_ = null;
656 if (!this.dragInfo_) 461 if (!this.dragInfo_)
657 return false; 462 return false;
658 463
659 // Make sure the dragging location is connected. 464 if (this.displayLayoutManager_.finalizePosition(this.dragInfo_.displayId))
660 var dragLayout = this.displayLayoutMap_[this.dragInfo_.displayId];
661 var baseDisplayId = dragLayout.isPrimary ? this.secondaryDisplayId_ :
662 this.primaryDisplayId_;
663
664 var baseLayout = this.displayLayoutMap_[baseDisplayId];
665 var baseDiv = baseLayout.div;
666 var draggingDiv = dragLayout.div;
667
668 // layoutType is always stored in the secondary layout.
669 var layoutType =
670 dragLayout.isPrimary ? baseLayout.layoutType : dragLayout.layoutType;
671
672 if (layoutType == options.DisplayLayoutType.LEFT ||
673 layoutType == options.DisplayLayoutType.RIGHT) {
674 var top = Math.max(
675 draggingDiv.offsetTop,
676 baseDiv.offsetTop - draggingDiv.offsetHeight + MIN_OFFSET_OVERLAP);
677 top = Math.min(
678 top, baseDiv.offsetTop + baseDiv.offsetHeight - MIN_OFFSET_OVERLAP);
679 draggingDiv.style.top = top + 'px';
680 } else {
681 var left = Math.max(
682 draggingDiv.offsetLeft,
683 baseDiv.offsetLeft - draggingDiv.offsetWidth + MIN_OFFSET_OVERLAP);
684 left = Math.min(
685 left,
686 baseDiv.offsetLeft + baseDiv.offsetWidth - MIN_OFFSET_OVERLAP);
687 draggingDiv.style.left = left + 'px';
688 }
689 if (dragLayout.originalPosition.x != draggingDiv.offsetLeft ||
690 dragLayout.originalPosition.y != draggingDiv.offsetTop) {
691 this.sendDragResult_(); 465 this.sendDragResult_();
692 }
693 466
694 this.dragInfo_ = null; 467 this.dragInfo_ = null;
695 468
696 return false; 469 return false;
697 }, 470 },
698 471
699 /** 472 /**
700 * Updates the description of selected display section for mirroring mode. 473 * Updates the description of selected display section for mirroring mode.
701 * @private 474 * @private
702 */ 475 */
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
738 resolution.disabled = true; 511 resolution.disabled = true;
739 }, 512 },
740 513
741 /** 514 /**
742 * Updates the description of selected display section for the selected 515 * Updates the description of selected display section for the selected
743 * display. 516 * display.
744 * @param {options.DisplayInfo} display The selected display object. 517 * @param {options.DisplayInfo} display The selected display object.
745 * @private 518 * @private
746 */ 519 */
747 updateSelectedDisplaySectionForDisplay_: function(display) { 520 updateSelectedDisplaySectionForDisplay_: function(display) {
748 var displayLayout = this.displayLayoutMap_[display.id]; 521 var displayLayout =
522 this.displayLayoutManager_.getDisplayLayout(display.id);
749 var arrow = $('display-configuration-arrow'); 523 var arrow = $('display-configuration-arrow');
750 arrow.hidden = false; 524 arrow.hidden = false;
751 // Adding 1 px to the position to fit the border line and the border in 525 // Adding 1 px to the position to fit the border line and the border in
752 // arrow precisely. 526 // arrow precisely.
753 arrow.style.top = $('display-configurations').offsetTop - 527 arrow.style.top = $('display-configurations').offsetTop -
754 arrow.offsetHeight / 2 + 'px'; 528 arrow.offsetHeight / 2 + 'px';
755 arrow.style.left = displayLayout.div.offsetLeft + 529 arrow.style.left = displayLayout.div.offsetLeft +
756 displayLayout.div.offsetWidth / 2 - arrow.offsetWidth / 2 + 'px'; 530 displayLayout.div.offsetWidth / 2 - arrow.offsetWidth / 2 + 'px';
757 531
758 $('display-options-set-primary').disabled = display.isPrimary; 532 $('display-options-set-primary').disabled = display.isPrimary;
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 if (i != numDisplays - 1) 671 if (i != numDisplays - 1)
898 div.classList.add('display-mirrored'); 672 div.classList.add('display-mirrored');
899 this.displaysView_.appendChild(div); 673 this.displaysView_.appendChild(div);
900 } 674 }
901 }, 675 },
902 676
903 /** 677 /**
904 * Creates a DisplayLayout object representing the display. 678 * Creates a DisplayLayout object representing the display.
905 * @param {!options.DisplayInfo} display 679 * @param {!options.DisplayInfo} display
906 * @param {!options.DisplayLayoutType} layoutType 680 * @param {!options.DisplayLayoutType} layoutType
681 * @param {string} parentId
907 * @return {!options.DisplayLayout} 682 * @return {!options.DisplayLayout}
908 * @private 683 * @private
909 */ 684 */
910 createDisplayLayout_: function(display, layoutType) { 685 createDisplayLayout_: function(display, layoutType, parentId) {
911 return { 686 return {
912 bounds: display.bounds, 687 bounds: display.bounds,
913 div: null, 688 div: null,
914 id: display.id, 689 id: display.id,
915 isPrimary: display.isPrimary,
916 layoutType: layoutType, 690 layoutType: layoutType,
917 name: display.name, 691 name: display.name,
918 originalPosition: {x: 0, y: 0} 692 offset: 0,
693 originalPosition: {x: 0, y: 0},
694 parentId: parentId
919 }; 695 };
920 }, 696 },
921 697
922 /** 698 /**
923 * Creates a div element representing the specified display.
924 * @param {!options.DisplayLayout} displayLayout
925 * @param {options.DisplayLayoutType} layoutType The layout type for the
926 * secondary display.
927 * @param {!options.DisplayPosition} offset The offset to the center of the
928 * display area.
929 * @private
930 */
931 createDisplayLayoutDiv_: function(displayLayout, layoutType, offset) {
932 var div = /** @type {!HTMLElement} */ (document.createElement('div'));
933 div.className = 'displays-display';
934 div.classList.toggle(
935 'displays-focused', displayLayout.id == this.focusedId_);
936
937 // div needs to be added to the DOM tree first, otherwise offsetHeight for
938 // nameContainer below cannot be computed.
939 this.displaysView_.appendChild(div);
940
941 var nameContainer = document.createElement('div');
942 nameContainer.textContent = displayLayout.name;
943 div.appendChild(nameContainer);
944
945 var bounds = displayLayout.bounds;
946 div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px';
947 var newHeight = Math.floor(bounds.height * this.visualScale_);
948 div.style.height = newHeight + 'px';
949 nameContainer.style.marginTop =
950 (newHeight - nameContainer.offsetHeight) / 2 + 'px';
951
952 div.onmousedown = this.onMouseDown_.bind(this);
953 div.ontouchstart = this.onTouchStart_.bind(this);
954
955 if (displayLayout.isPrimary) {
956 div.style.left =
957 Math.floor(bounds.left * this.visualScale_) + offset.x + 'px';
958 div.style.top =
959 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px';
960 } else {
961 // Don't trust the secondary display's x or y, because it may cause a
962 // 1px gap due to rounding, which will create a fake update on end
963 // dragging. See crbug.com/386401
964 var primaryDiv = this.displayLayoutMap_[this.primaryDisplayId_].div;
965 switch (layoutType) {
966 case options.DisplayLayoutType.TOP:
967 div.style.left =
968 Math.floor(bounds.left * this.visualScale_) + offset.x + 'px';
969 div.style.top = primaryDiv.offsetTop - div.offsetHeight + 'px';
970 break;
971 case options.DisplayLayoutType.RIGHT:
972 div.style.left =
973 primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px';
974 div.style.top =
975 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px';
976 break;
977 case options.DisplayLayoutType.BOTTOM:
978 div.style.left =
979 Math.floor(bounds.left * this.visualScale_) + offset.x + 'px';
980 div.style.top =
981 primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px';
982 break;
983 case options.DisplayLayoutType.LEFT:
984 div.style.left = primaryDiv.offsetLeft - div.offsetWidth + 'px';
985 div.style.top =
986 Math.floor(bounds.top * this.visualScale_) + offset.y + 'px';
987 break;
988 }
989 }
990
991 displayLayout.div = div;
992 displayLayout.originalPosition.x = div.offsetLeft;
993 displayLayout.originalPosition.y = div.offsetTop;
994 },
995
996 /**
997 * Layouts the display rectangles according to the current layout_. 699 * Layouts the display rectangles according to the current layout_.
998 * @param {options.DisplayLayoutType} layoutType 700 * @param {options.DisplayLayoutType} layoutType
999 * @private 701 * @private
1000 */ 702 */
1001 layoutDisplays_: function(layoutType) { 703 layoutDisplays_: function(layoutType) {
1002 var maxWidth = 0; 704 var maxWidth = 0;
1003 var maxHeight = 0; 705 var maxHeight = 0;
1004 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; 706 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0};
1005 this.primaryDisplayId_ = ''; 707 var primaryDisplayId = '';
1006 this.secondaryDisplayId_ = '';
1007 for (var i = 0; i < this.displays_.length; i++) { 708 for (var i = 0; i < this.displays_.length; i++) {
1008 var display = this.displays_[i]; 709 var display = this.displays_[i];
1009 if (display.isPrimary) 710 if (display.isPrimary && primaryDisplayId == '')
1010 this.primaryDisplayId_ = display.id; 711 primaryDisplayId = display.id;
1011 else if (this.secondaryDisplayId_ == '')
1012 this.secondaryDisplayId_ = display.id;
1013 712
1014 var bounds = display.bounds; 713 var bounds = display.bounds;
1015 boundingBox.left = Math.min(boundingBox.left, bounds.left); 714 boundingBox.left = Math.min(boundingBox.left, bounds.left);
1016 boundingBox.right = 715 boundingBox.right =
1017 Math.max(boundingBox.right, bounds.left + bounds.width); 716 Math.max(boundingBox.right, bounds.left + bounds.width);
1018 boundingBox.top = Math.min(boundingBox.top, bounds.top); 717 boundingBox.top = Math.min(boundingBox.top, bounds.top);
1019 boundingBox.bottom = 718 boundingBox.bottom =
1020 Math.max(boundingBox.bottom, bounds.top + bounds.height); 719 Math.max(boundingBox.bottom, bounds.top + bounds.height);
1021 maxWidth = Math.max(maxWidth, bounds.width); 720 maxWidth = Math.max(maxWidth, bounds.width);
1022 maxHeight = Math.max(maxHeight, bounds.height); 721 maxHeight = Math.max(maxHeight, bounds.height);
1023 } 722 }
1024 if (this.primaryDisplayId_ == '') 723 if (primaryDisplayId == '')
1025 return; 724 return;
1026 725
1027 // Make the margin around the bounding box. 726 // Make the margin around the bounding box.
1028 var areaWidth = boundingBox.right - boundingBox.left + maxWidth; 727 var areaWidth = boundingBox.right - boundingBox.left + maxWidth;
1029 var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight; 728 var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight;
1030 729
1031 // Calculates the scale by the width since horizontal size is more strict. 730 // Calculates the scale by the width since horizontal size is more strict.
1032 // TODO(mukai): Adds the check of vertical size in case. 731 // TODO(mukai): Adds the check of vertical size in case.
1033 this.visualScale_ = Math.min( 732 this.visualScale_ = Math.min(
1034 VISUAL_SCALE, this.displaysView_.offsetWidth / areaWidth); 733 VISUAL_SCALE, this.displaysView_.offsetWidth / areaWidth);
1035 734
1036 // Prepare enough area for thisplays_view by adding the maximum height. 735 // Prepare enough area for thisplays_view by adding the maximum height.
1037 this.displaysView_.style.height = 736 this.displaysView_.style.height =
1038 Math.ceil(areaHeight * this.visualScale_) + 'px'; 737 Math.ceil(areaHeight * this.visualScale_) + 'px';
1039 738
1040 // Centering the bounding box of the display rectangles. 739 // Centering the bounding box of the display rectangles.
1041 var offset = { 740 var offset = {
1042 x: Math.floor( 741 x: Math.floor(
1043 this.displaysView_.offsetWidth / 2 - 742 this.displaysView_.offsetWidth / 2 -
1044 (boundingBox.right + boundingBox.left) * this.visualScale_ / 2), 743 (boundingBox.right + boundingBox.left) * this.visualScale_ / 2),
1045 y: Math.floor( 744 y: Math.floor(
1046 this.displaysView_.offsetHeight / 2 - 745 this.displaysView_.offsetHeight / 2 -
1047 (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2) 746 (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2)
1048 }; 747 };
1049 748
1050 // Layout the display rectangles. First layout the primary display and 749 // Create the layout manager.
1051 // then layout any secondary displays. 750 this.displayLayoutManager_ =
1052 this.createDisplayLayoutDiv_( 751 new options.DisplayLayoutManager(this.visualScale_);
1053 this.displayLayoutMap_[this.primaryDisplayId_], layoutType, offset); 752
753 // Create the display layouts.
1054 for (var i = 0; i < this.displays_.length; i++) { 754 for (var i = 0; i < this.displays_.length; i++) {
1055 if (!this.displays_[i].isPrimary) { 755 var display = this.displays_[i];
1056 this.createDisplayLayoutDiv_( 756 var parentId = display.isPrimary ? '' : primaryDisplayId;
1057 this.displayLayoutMap_[this.displays_[i].id], layoutType, offset); 757 var layout = this.createDisplayLayout_(display, layoutType, parentId);
1058 } 758 this.displayLayoutManager_.addDisplayLayout(layout);
759 }
760
761 // Create the display divs.
762 this.displayLayoutManager_.createDisplayLayoutDivs(
763 this.displaysView_, offset);
764
765 // Set the div callbacks and highlight the focused div.
766 for (var i = 0; i < this.displays_.length; i++) {
767 var id = this.displays_[i].id;
768 var div = this.displayLayoutManager_.getDisplayLayout(id).div;
769 div.onmousedown = this.onMouseDown_.bind(this);
770 div.ontouchstart = this.onTouchStart_.bind(this);
771 if (id == this.focusedId_)
772 div.classList.toggle('displays-focused', true);
xiyuan 2016/01/26 18:06:53 nit: Can we get rid of the "if" and just do div.c
stevenjb 2016/01/26 19:36:15 Done.
1059 } 773 }
1060 }, 774 },
1061 775
1062 /** 776 /**
1063 * Called when the display arrangement has changed. 777 * Called when the display arrangement has changed.
1064 * @param {options.MultiDisplayMode} mode multi display mode. 778 * @param {options.MultiDisplayMode} mode multi display mode.
1065 * @param {!Array<!options.DisplayInfo>} displays The list of the display 779 * @param {!Array<!options.DisplayInfo>} displays The list of the display
1066 * information. 780 * information.
1067 * @param {options.DisplayLayoutType} layoutType The layout strategy. 781 * @param {options.DisplayLayoutType} layoutType The layout type for the
782 * secondary display.
1068 * @param {number} offset The offset of the secondary display. 783 * @param {number} offset The offset of the secondary display.
1069 * @private 784 * @private
1070 */ 785 */
1071 onDisplayChanged_: function(mode, displays, layoutType, offset) { 786 onDisplayChanged_: function(mode, displays, layoutType, offset) {
1072 if (!this.visible) 787 if (!this.visible)
1073 return; 788 return;
1074 789
1075 this.displays_ = displays; 790 this.displays_ = displays;
1076 this.displayLayoutMap_ = {};
1077 for (var i = 0; i < displays.length; i++) {
1078 var display = displays[i];
1079 this.displayLayoutMap_[display.id] =
1080 this.createDisplayLayout_(display, layoutType);
1081 }
1082 791
1083 var mirroring = mode == options.MultiDisplayMode.MIRRORING; 792 var mirroring = mode == options.MultiDisplayMode.MIRRORING;
1084 var unifiedDesktopEnabled = mode == options.MultiDisplayMode.UNIFIED; 793 var unifiedDesktopEnabled = mode == options.MultiDisplayMode.UNIFIED;
1085 794
1086 // Focus to the first display next to the primary one when |displays_| 795 // Focus to the first display next to the primary one when |displays_|
1087 // is updated. 796 // is updated.
1088 if (mirroring) { 797 if (mirroring) {
1089 this.focusedId_ = ''; 798 this.focusedId_ = '';
1090 } else if ( 799 } else if (
1091 this.focusedId_ == '' || this.mirroring_ != mirroring || 800 this.focusedId_ == '' || this.mirroring_ != mirroring ||
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1128 mode, displays, layoutType, offset) { 837 mode, displays, layoutType, offset) {
1129 DisplayOptions.getInstance().onDisplayChanged_( 838 DisplayOptions.getInstance().onDisplayChanged_(
1130 mode, displays, layoutType, offset); 839 mode, displays, layoutType, offset);
1131 }; 840 };
1132 841
1133 // Export 842 // Export
1134 return { 843 return {
1135 DisplayOptions: DisplayOptions 844 DisplayOptions: DisplayOptions
1136 }; 845 };
1137 }); 846 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698