OLD | NEW |
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 * @typedef {{ | 8 * @typedef {{ |
9 * availableColorProfiles: Array.<{profileId: number, name: string}>, | 9 * availableColorProfiles: Array.<{profileId: number, name: string}>, |
10 * colorProfile: number, | 10 * colorProfile: number, |
(...skipping 748 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 div.style.height = height + 'px'; | 759 div.style.height = height + 'px'; |
760 div.style.zIndex = i; | 760 div.style.zIndex = i; |
761 // set 'display-mirrored' class for the background display rectangles. | 761 // set 'display-mirrored' class for the background display rectangles. |
762 if (i != numDisplays - 1) | 762 if (i != numDisplays - 1) |
763 div.classList.add('display-mirrored'); | 763 div.classList.add('display-mirrored'); |
764 this.displaysView_.appendChild(div); | 764 this.displaysView_.appendChild(div); |
765 } | 765 } |
766 }, | 766 }, |
767 | 767 |
768 /** | 768 /** |
| 769 * Creates a div element representing the specified display. |
| 770 * @param {Object} display The display object. |
| 771 * @param {boolean} focused True if it's focused. |
| 772 * @private |
| 773 */ |
| 774 createDisplayRectangle_: function(display, focused) { |
| 775 var div = document.createElement('div'); |
| 776 display.div = div; |
| 777 div.className = 'displays-display'; |
| 778 if (focused) |
| 779 div.classList.add('displays-focused'); |
| 780 |
| 781 // div needs to be added to the DOM tree first, otherwise offsetHeight for |
| 782 // nameContainer below cannot be computed. |
| 783 this.displaysView_.appendChild(div); |
| 784 |
| 785 var nameContainer = document.createElement('div'); |
| 786 nameContainer.textContent = display.name; |
| 787 div.appendChild(nameContainer); |
| 788 div.style.width = Math.floor(display.width * this.visualScale_) + 'px'; |
| 789 var newHeight = Math.floor(display.height * this.visualScale_); |
| 790 div.style.height = newHeight + 'px'; |
| 791 nameContainer.style.marginTop = |
| 792 (newHeight - nameContainer.offsetHeight) / 2 + 'px'; |
| 793 |
| 794 div.onmousedown = this.onMouseDown_.bind(this); |
| 795 div.ontouchstart = this.onTouchStart_.bind(this); |
| 796 return div; |
| 797 }, |
| 798 |
| 799 /** |
769 * Layouts the display rectangles according to the current layout_. | 800 * Layouts the display rectangles according to the current layout_. |
770 * @private | 801 * @private |
771 */ | 802 */ |
772 layoutDisplays_: function() { | 803 layoutDisplays_: function() { |
773 var maxWidth = 0; | 804 var maxWidth = 0; |
774 var maxHeight = 0; | 805 var maxHeight = 0; |
775 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; | 806 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; |
| 807 this.primaryDisplay_ = null; |
| 808 this.secondaryDisplay_ = null; |
| 809 var focusedDisplay = null; |
776 for (var i = 0; i < this.displays_.length; i++) { | 810 for (var i = 0; i < this.displays_.length; i++) { |
777 var display = this.displays_[i]; | 811 var display = this.displays_[i]; |
| 812 if (display.isPrimary) |
| 813 this.primaryDisplay_ = display; |
| 814 else |
| 815 this.secondaryDisplay_ = display; |
| 816 if (i == this.focusedIndex_) |
| 817 focusedDisplay = display; |
| 818 |
778 boundingBox.left = Math.min(boundingBox.left, display.x); | 819 boundingBox.left = Math.min(boundingBox.left, display.x); |
779 boundingBox.right = Math.max( | 820 boundingBox.right = Math.max( |
780 boundingBox.right, display.x + display.width); | 821 boundingBox.right, display.x + display.width); |
781 boundingBox.top = Math.min(boundingBox.top, display.y); | 822 boundingBox.top = Math.min(boundingBox.top, display.y); |
782 boundingBox.bottom = Math.max( | 823 boundingBox.bottom = Math.max( |
783 boundingBox.bottom, display.y + display.height); | 824 boundingBox.bottom, display.y + display.height); |
784 maxWidth = Math.max(maxWidth, display.width); | 825 maxWidth = Math.max(maxWidth, display.width); |
785 maxHeight = Math.max(maxHeight, display.height); | 826 maxHeight = Math.max(maxHeight, display.height); |
786 } | 827 } |
| 828 if (!this.primaryDisplay_) |
| 829 return; |
787 | 830 |
788 // Make the margin around the bounding box. | 831 // Make the margin around the bounding box. |
789 var areaWidth = boundingBox.right - boundingBox.left + maxWidth; | 832 var areaWidth = boundingBox.right - boundingBox.left + maxWidth; |
790 var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight; | 833 var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight; |
791 | 834 |
792 // Calculates the scale by the width since horizontal size is more strict. | 835 // Calculates the scale by the width since horizontal size is more strict. |
793 // TODO(mukai): Adds the check of vertical size in case. | 836 // TODO(mukai): Adds the check of vertical size in case. |
794 this.visualScale_ = Math.min( | 837 this.visualScale_ = Math.min( |
795 VISUAL_SCALE, this.displaysView_.offsetWidth / areaWidth); | 838 VISUAL_SCALE, this.displaysView_.offsetWidth / areaWidth); |
796 | 839 |
797 // Prepare enough area for thisplays_view by adding the maximum height. | 840 // Prepare enough area for thisplays_view by adding the maximum height. |
798 this.displaysView_.style.height = | 841 this.displaysView_.style.height = |
799 Math.ceil(areaHeight * this.visualScale_) + 'px'; | 842 Math.ceil(areaHeight * this.visualScale_) + 'px'; |
800 | 843 |
801 var boundingCenter = { | |
802 x: Math.floor((boundingBox.right + boundingBox.left) * | |
803 this.visualScale_ / 2), | |
804 y: Math.floor((boundingBox.bottom + boundingBox.top) * | |
805 this.visualScale_ / 2) | |
806 }; | |
807 | |
808 // Centering the bounding box of the display rectangles. | 844 // Centering the bounding box of the display rectangles. |
809 var offset = { | 845 var offset = { |
810 x: Math.floor(this.displaysView_.offsetWidth / 2 - | 846 x: Math.floor(this.displaysView_.offsetWidth / 2 - |
811 (boundingBox.right + boundingBox.left) * this.visualScale_ / 2), | 847 (boundingBox.right + boundingBox.left) * this.visualScale_ / 2), |
812 y: Math.floor(this.displaysView_.offsetHeight / 2 - | 848 y: Math.floor(this.displaysView_.offsetHeight / 2 - |
813 (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2) | 849 (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2) |
814 }; | 850 }; |
815 | 851 |
816 for (var i = 0; i < this.displays_.length; i++) { | 852 // Layouting the display rectangles. First layout the primaryDisplay and |
817 var display = this.displays_[i]; | 853 // then layout the secondary which is attaching to the primary. |
818 var div = document.createElement('div'); | 854 var primaryDiv = this.createDisplayRectangle_( |
819 display.div = div; | 855 this.primaryDisplay_, this.primaryDisplay_ == focusedDisplay); |
| 856 primaryDiv.style.left = |
| 857 Math.floor(this.primaryDisplay_.x * this.visualScale_) + |
| 858 offset.x + 'px'; |
| 859 primaryDiv.style.top = |
| 860 Math.floor(this.primaryDisplay_.y * this.visualScale_) + |
| 861 offset.y + 'px'; |
| 862 this.primaryDisplay_.originalPosition = { |
| 863 x: primaryDiv.offsetLeft, y: primaryDiv.offsetTop}; |
820 | 864 |
821 div.className = 'displays-display'; | 865 if (this.secondaryDisplay_) { |
822 if (i == this.focusedIndex_) | 866 var secondaryDiv = this.createDisplayRectangle_( |
823 div.classList.add('displays-focused'); | 867 this.secondaryDisplay_, this.secondaryDisplay_ == focusedDisplay); |
824 | 868 // Don't trust the secondary display's x or y, because it may cause a |
825 if (display.isPrimary) { | 869 // 1px gap due to rounding, which will create a fake update on end |
826 this.primaryDisplay_ = display; | 870 // dragging. See crbug.com/386401 |
827 } else { | 871 switch (this.layout_) { |
828 this.secondaryDisplay_ = display; | 872 case options.SecondaryDisplayLayout.TOP: |
| 873 secondaryDiv.style.left = |
| 874 Math.floor(this.secondaryDisplay_.x * this.visualScale_) + |
| 875 offset.x + 'px'; |
| 876 secondaryDiv.style.top = |
| 877 primaryDiv.offsetTop - secondaryDiv.offsetHeight + 'px'; |
| 878 break; |
| 879 case options.SecondaryDisplayLayout.RIGHT: |
| 880 secondaryDiv.style.left = |
| 881 primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px'; |
| 882 secondaryDiv.style.top = |
| 883 Math.floor(this.secondaryDisplay_.y * this.visualScale_) + |
| 884 offset.y + 'px'; |
| 885 break; |
| 886 case options.SecondaryDisplayLayout.BOTTOM: |
| 887 secondaryDiv.style.left = |
| 888 Math.floor(this.secondaryDisplay_.x * this.visualScale_) + |
| 889 offset.x + 'px'; |
| 890 secondaryDiv.style.top = |
| 891 primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px'; |
| 892 break; |
| 893 case options.SecondaryDisplayLayout.LEFT: |
| 894 secondaryDiv.style.left = |
| 895 primaryDiv.offsetLeft - secondaryDiv.offsetWidth + 'px'; |
| 896 secondaryDiv.style.top = |
| 897 Math.floor(this.secondaryDisplay_.y * this.visualScale_) + |
| 898 offset.y + 'px'; |
| 899 break; |
829 } | 900 } |
830 var displayNameContainer = document.createElement('div'); | 901 this.secondaryDisplay_.originalPosition = { |
831 displayNameContainer.textContent = display.name; | 902 x: secondaryDiv.offsetLeft, y: secondaryDiv.offsetTop}; |
832 div.appendChild(displayNameContainer); | |
833 display.nameContainer = displayNameContainer; | |
834 display.div.style.width = | |
835 Math.floor(display.width * this.visualScale_) + 'px'; | |
836 var newHeight = Math.floor(display.height * this.visualScale_); | |
837 display.div.style.height = newHeight + 'px'; | |
838 div.style.left = | |
839 Math.floor(display.x * this.visualScale_) + offset.x + 'px'; | |
840 div.style.top = | |
841 Math.floor(display.y * this.visualScale_) + offset.y + 'px'; | |
842 display.nameContainer.style.marginTop = | |
843 (newHeight - display.nameContainer.offsetHeight) / 2 + 'px'; | |
844 | |
845 div.onmousedown = this.onMouseDown_.bind(this); | |
846 div.ontouchstart = this.onTouchStart_.bind(this); | |
847 | |
848 this.displaysView_.appendChild(div); | |
849 | |
850 // Set the margin top to place the display name at the middle of the | |
851 // rectangle. Note that this has to be done after it's added into the | |
852 // |displaysView_|. Otherwise its offsetHeight is yet 0. | |
853 displayNameContainer.style.marginTop = | |
854 (div.offsetHeight - displayNameContainer.offsetHeight) / 2 + 'px'; | |
855 display.originalPosition = {x: div.offsetLeft, y: div.offsetTop}; | |
856 } | 903 } |
857 }, | 904 }, |
858 | 905 |
859 /** | 906 /** |
860 * Called when the display arrangement has changed. | 907 * Called when the display arrangement has changed. |
861 * @param {boolean} mirroring Whether current mode is mirroring or not. | 908 * @param {boolean} mirroring Whether current mode is mirroring or not. |
862 * @param {Array.<options.DisplayInfo>} displays The list of the display | 909 * @param {Array.<options.DisplayInfo>} displays The list of the display |
863 * information. | 910 * information. |
864 * @param {options.SecondaryDisplayLayout} layout The layout strategy. | 911 * @param {options.SecondaryDisplayLayout} layout The layout strategy. |
865 * @param {number} offset The offset of the secondary display. | 912 * @param {number} offset The offset of the secondary display. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 mirroring, displays, layout, offset) { | 956 mirroring, displays, layout, offset) { |
910 DisplayOptions.getInstance().onDisplayChanged_( | 957 DisplayOptions.getInstance().onDisplayChanged_( |
911 mirroring, displays, layout, offset); | 958 mirroring, displays, layout, offset); |
912 }; | 959 }; |
913 | 960 |
914 // Export | 961 // Export |
915 return { | 962 return { |
916 DisplayOptions: DisplayOptions | 963 DisplayOptions: DisplayOptions |
917 }; | 964 }; |
918 }); | 965 }); |
OLD | NEW |