| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 cr.define('options', function() { | 
|  | 6   var OptionsPage = options.OptionsPage; | 
|  | 7 | 
|  | 8   // The scale ratio of the display rectangle to its original size. | 
|  | 9   /** @const */ var VISUAL_SCALE = 1 / 10; | 
|  | 10 | 
|  | 11   /** | 
|  | 12    * Enumeration of secondary display layout.  The value has to be same as the | 
|  | 13    * values in ash/monitor/monitor_controller.cc. | 
|  | 14    * @enum {number} | 
|  | 15    */ | 
|  | 16   var SecondaryDisplayLayout = { | 
|  | 17     TOP: 0, | 
|  | 18     RIGHT: 1, | 
|  | 19     BOTTOM: 2, | 
|  | 20     LEFT: 3 | 
|  | 21   }; | 
|  | 22 | 
|  | 23   /** | 
|  | 24    * Encapsulated handling of the 'Display' page. | 
|  | 25    * @constructor | 
|  | 26    */ | 
|  | 27   function DisplayOptions() { | 
|  | 28     OptionsPage.call(this, 'display', | 
|  | 29                      loadTimeData.getString('displayOptionsPageTabTitle'), | 
|  | 30                      'display-options'); | 
|  | 31     this.mirroring_ = false; | 
|  | 32     this.focused_index_ = null; | 
|  | 33     this.displays_ = []; | 
|  | 34   } | 
|  | 35 | 
|  | 36   cr.addSingletonGetter(DisplayOptions); | 
|  | 37 | 
|  | 38   DisplayOptions.prototype = { | 
|  | 39     __proto__: OptionsPage.prototype, | 
|  | 40 | 
|  | 41     /** | 
|  | 42      * Initialize the page. | 
|  | 43      */ | 
|  | 44     initializePage: function() { | 
|  | 45       OptionsPage.prototype.initializePage.call(this); | 
|  | 46 | 
|  | 47       $('display-options-confirm').onclick = function() { | 
|  | 48         OptionsPage.closeOverlay(); | 
|  | 49       }; | 
|  | 50 | 
|  | 51       $('display-options-toggle-mirroring').onclick = (function() { | 
|  | 52         this.mirroring_ = !this.mirroring_; | 
|  | 53         chrome.send('setMirroring', [this.mirroring_]); | 
|  | 54       }).bind(this); | 
|  | 55 | 
|  | 56       chrome.send('getDisplayInfo'); | 
|  | 57     }, | 
|  | 58 | 
|  | 59     /** | 
|  | 60      * Mouse move handler for dragging display rectangle. | 
|  | 61      * @private | 
|  | 62      * @param {Event} e The mouse move event. | 
|  | 63      */ | 
|  | 64     onMouseMove_: function(e) { | 
|  | 65       if (!this.dragging_) | 
|  | 66         return true; | 
|  | 67 | 
|  | 68       var index = -1; | 
|  | 69       for (var i = 0; i < this.displays_.length; i++) { | 
|  | 70         if (this.displays_[i] == this.dragging_.display) { | 
|  | 71           index = i; | 
|  | 72           break; | 
|  | 73         } | 
|  | 74       } | 
|  | 75       if (index < 0) | 
|  | 76         return true; | 
|  | 77 | 
|  | 78       // Note that current code of moving display-rectangles doesn't work | 
|  | 79       // if there are >=3 displays.  This is our assumption for M21. | 
|  | 80       // TODO(mukai): Fix the code to allow >=3 displays. | 
|  | 81       var mouse_position = { | 
|  | 82         x: e.pageX - this.dragging_.offset.x, | 
|  | 83         y: e.pageY - this.dragging_.offset.y | 
|  | 84       }; | 
|  | 85       var new_position = { | 
|  | 86         x: mouse_position.x - this.dragging_.click_location.x, | 
|  | 87         y: mouse_position.y - this.dragging_.click_location.y | 
|  | 88       }; | 
|  | 89 | 
|  | 90       var primary_div = this.displays_[0].div; | 
|  | 91       var display = this.dragging_.display; | 
|  | 92 | 
|  | 93       // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of | 
|  | 94       // the primary display, and decide which area the display should reside. | 
|  | 95       var diagonal_slope = primary_div.offsetHeight / primary_div.offsetWidth; | 
|  | 96       var top_down_intercept = | 
|  | 97           primary_div.offsetTop - primary_div.offsetLeft * diagonal_slope; | 
|  | 98       var bottom_up_intercept = primary_div.offsetTop + | 
|  | 99           primary_div.offsetHeight + primary_div.offsetLeft * diagonal_slope; | 
|  | 100 | 
|  | 101       if (mouse_position.y > | 
|  | 102           top_down_intercept + mouse_position.x * diagonal_slope) { | 
|  | 103         if (mouse_position.y > | 
|  | 104             bottom_up_intercept - mouse_position.x * diagonal_slope) | 
|  | 105           this.layout_ = SecondaryDisplayLayout.BOTTOM; | 
|  | 106         else | 
|  | 107           this.layout_ = SecondaryDisplayLayout.LEFT; | 
|  | 108       } else { | 
|  | 109         if (mouse_position.y > | 
|  | 110             bottom_up_intercept - mouse_position.x * diagonal_slope) | 
|  | 111           this.layout_ = SecondaryDisplayLayout.RIGHT; | 
|  | 112         else | 
|  | 113           this.layout_ = SecondaryDisplayLayout.TOP; | 
|  | 114       } | 
|  | 115 | 
|  | 116       if (this.layout_ == SecondaryDisplayLayout.LEFT || | 
|  | 117           this.layout_ == SecondaryDisplayLayout.RIGHT) { | 
|  | 118         if (new_position.y > primary_div.offsetTop + primary_div.offsetHeight) | 
|  | 119           this.layout_ = SecondaryDisplayLayout.BOTTOM; | 
|  | 120         else if (new_position.y + display.div.offsetHeight < | 
|  | 121                  primary_div.offsetTop) | 
|  | 122           this.layout_ = SecondaryDisplayLayout.TOP; | 
|  | 123       } else { | 
|  | 124         if (new_position.y > primary_div.offsetLeft + primary_div.offsetWidth) | 
|  | 125           this.layout_ = SecondaryDisplayLayout.RIGHT; | 
|  | 126         else if (new_position.y + display.div.offsetWidth < | 
|  | 127                    primary_div.offstLeft) | 
|  | 128           this.layout_ = SecondaryDisplayLayout.LEFT; | 
|  | 129       } | 
|  | 130 | 
|  | 131       switch (this.layout_) { | 
|  | 132       case SecondaryDisplayLayout.RIGHT: | 
|  | 133         display.div.style.left = | 
|  | 134             primary_div.offsetLeft + primary_div.offsetWidth + 'px'; | 
|  | 135         display.div.style.top = new_position.y + 'px'; | 
|  | 136         break; | 
|  | 137       case SecondaryDisplayLayout.LEFT: | 
|  | 138         display.div.style.left = | 
|  | 139             primary_div.offsetLeft - display.div.offsetWidth + 'px'; | 
|  | 140         display.div.style.top = new_position.y + 'px'; | 
|  | 141         break; | 
|  | 142       case SecondaryDisplayLayout.TOP: | 
|  | 143         display.div.style.top = | 
|  | 144             primary_div.offsetTop - display.div.offsetHeight + 'px'; | 
|  | 145         display.div.style.left = new_position.x + 'px'; | 
|  | 146         break; | 
|  | 147       case SecondaryDisplayLayout.BOTTOM: | 
|  | 148         display.div.style.top = | 
|  | 149             primary_div.offsetTop + primary_div.offsetHeight + 'px'; | 
|  | 150         display.div.style.left = new_position.x + 'px'; | 
|  | 151         break; | 
|  | 152       } | 
|  | 153 | 
|  | 154       return false; | 
|  | 155     }, | 
|  | 156 | 
|  | 157     /** | 
|  | 158      * Mouse down handler for dragging display rectangle. | 
|  | 159      * @private | 
|  | 160      * @param {Event} e The mouse down event. | 
|  | 161      */ | 
|  | 162     onMouseDown_: function(e) { | 
|  | 163       if (this.mirroring_) | 
|  | 164         return true; | 
|  | 165 | 
|  | 166       if (e.button != 0) | 
|  | 167         return true; | 
|  | 168 | 
|  | 169       if (e.target == this.displays_view_) | 
|  | 170         return true; | 
|  | 171 | 
|  | 172       for (var i = 0; i < this.displays_.length; i++) { | 
|  | 173         var display = this.displays_[i]; | 
|  | 174         if (display.div == e.target) { | 
|  | 175           // Do not drag the primary monitor. | 
|  | 176           if (i == 0) | 
|  | 177             return true; | 
|  | 178 | 
|  | 179           this.focused_index_ = i; | 
|  | 180           this.dragging_ = { | 
|  | 181             display: display, | 
|  | 182             click_location: {x: e.offsetX, y: e.offsetY}, | 
|  | 183             offset: {x: e.pageX - e.offsetX - display.div.offsetLeft, | 
|  | 184                      y: e.pageY - e.offsetY - display.div.offsetTop} | 
|  | 185           }; | 
|  | 186           if (display.div.className.indexOf('displays-focused') == -1) | 
|  | 187             display.div.className += ' displays-focused'; | 
|  | 188         } else if (display.div.className.indexOf('displays-focused') >= 0) { | 
|  | 189           // We can assume that '-primary' monitor doesn't have '-focused'. | 
|  | 190           this.displays_[i].div.className = 'displays-display'; | 
|  | 191         } | 
|  | 192       } | 
|  | 193       return false; | 
|  | 194     }, | 
|  | 195 | 
|  | 196     /** | 
|  | 197      * Mouse up handler for dragging display rectangle. | 
|  | 198      * @private | 
|  | 199      * @param {Event} e The mouse up event. | 
|  | 200      */ | 
|  | 201     onMouseUp_: function(e) { | 
|  | 202       if (this.dragging_) { | 
|  | 203         this.dragging_ = null; | 
|  | 204         chrome.send('setDisplayLayout', [this.layout_]); | 
|  | 205       } | 
|  | 206       return false; | 
|  | 207     }, | 
|  | 208 | 
|  | 209     /** | 
|  | 210      * Clears the drawing area for display rectangles. | 
|  | 211      * @private | 
|  | 212      */ | 
|  | 213     resetDisplaysView_: function() { | 
|  | 214       var displays_view_host = $('display-options-displays-view-host'); | 
|  | 215       displays_view_host.removeChild(displays_view_host.firstChild); | 
|  | 216       this.displays_view_ = document.createElement('div'); | 
|  | 217       this.displays_view_.id = 'display-options-displays-view'; | 
|  | 218       this.displays_view_.onmousemove = this.onMouseMove_.bind(this); | 
|  | 219       this.displays_view_.onmousedown = this.onMouseDown_.bind(this); | 
|  | 220       this.displays_view_.onmouseup = this.onMouseUp_.bind(this); | 
|  | 221       displays_view_host.appendChild(this.displays_view_); | 
|  | 222     }, | 
|  | 223 | 
|  | 224     /** | 
|  | 225      * Lays out the display rectangles for mirroring. | 
|  | 226      * @private | 
|  | 227      */ | 
|  | 228     layoutMirroringDisplays_: function() { | 
|  | 229       // The width/height should be same as the primary display: | 
|  | 230       var width = this.displays_[0].width * VISUAL_SCALE; | 
|  | 231       var height = this.displays_[0].height * VISUAL_SCALE; | 
|  | 232 | 
|  | 233       this.displays_view_.style.height = | 
|  | 234         height + this.displays_.length * 2 + 'px'; | 
|  | 235 | 
|  | 236       for (var i = 0; i < this.displays_.length; i++) { | 
|  | 237         var div = document.createElement('div'); | 
|  | 238         this.displays_[i].div = div; | 
|  | 239         div.className = 'displays-display'; | 
|  | 240         div.style.top = i * 2 + 'px'; | 
|  | 241         div.style.left = i * 2 + 'px'; | 
|  | 242         div.style.width = width + 'px'; | 
|  | 243         div.style.height = height + 'px'; | 
|  | 244         div.style.zIndex = i; | 
|  | 245         if (i == this.displays_.length - 1) | 
|  | 246           div.className += ' displays-primary'; | 
|  | 247         this.displays_view_.appendChild(div); | 
|  | 248       } | 
|  | 249     }, | 
|  | 250 | 
|  | 251     /** | 
|  | 252      * Layouts the display rectangles according to the current layout_. | 
|  | 253      * @private | 
|  | 254      */ | 
|  | 255     layoutDisplays_: function() { | 
|  | 256       var total_size = {width: 0, height: 0}; | 
|  | 257       for (var i = 0; i < this.displays_.length; i++) { | 
|  | 258         total_size.width += this.displays_[i].width * VISUAL_SCALE; | 
|  | 259         total_size.height += this.displays_[i].height * VISUAL_SCALE; | 
|  | 260       } | 
|  | 261 | 
|  | 262       this.displays_view_.style.width = total_size.width + 'px'; | 
|  | 263       this.displays_view_.style.height = total_size.height + 'px'; | 
|  | 264 | 
|  | 265       var base_point = {x: 0, y: 0}; | 
|  | 266       if (this.layout_ == SecondaryDisplayLayout.LEFT) | 
|  | 267         base_point.x = total_size.width; | 
|  | 268       else if (this.layout_ == SecondaryDisplayLayout.TOP) | 
|  | 269         base_point.y = total_size.height; | 
|  | 270 | 
|  | 271       for (var i = 0; i < this.displays_.length; i++) { | 
|  | 272         var display = this.displays_[i]; | 
|  | 273         var div = document.createElement('div'); | 
|  | 274         display.div = div; | 
|  | 275 | 
|  | 276         div.className = 'displays-display'; | 
|  | 277         if (i == 0) | 
|  | 278           div.className += ' displays-primary'; | 
|  | 279         else if (i == this.focused_index_) | 
|  | 280           div.className += ' displays-focused'; | 
|  | 281         div.style.width = display.width * VISUAL_SCALE + 'px'; | 
|  | 282         div.style.height = display.height * VISUAL_SCALE + 'px'; | 
|  | 283         div.style.lineHeight = div.style.height; | 
|  | 284         switch (this.layout_) { | 
|  | 285         case SecondaryDisplayLayout.RIGHT: | 
|  | 286           display.div.style.top = '0'; | 
|  | 287           display.div.style.left = base_point.x + 'px'; | 
|  | 288           base_point.x += display.width * VISUAL_SCALE; | 
|  | 289           break; | 
|  | 290         case SecondaryDisplayLayout.LEFT: | 
|  | 291           display.div.style.top = '0'; | 
|  | 292           base_point.x -= display.width * VISUAL_SCALE; | 
|  | 293           display.div.style.left = base_point.x + 'px'; | 
|  | 294           break; | 
|  | 295         case SecondaryDisplayLayout.TOP: | 
|  | 296           display.div.style.left = '0'; | 
|  | 297           base_point.y -= display.height * VISUAL_SCALE; | 
|  | 298           display.div.style.top = base_point.y + 'px'; | 
|  | 299           break; | 
|  | 300         case SecondaryDisplayLayout.BOTTOM: | 
|  | 301           display.div.style.left = '0'; | 
|  | 302           display.div.style.top = base_point.y + 'px'; | 
|  | 303           base_point.y += display.height * VISUAL_SCALE; | 
|  | 304           break; | 
|  | 305         } | 
|  | 306 | 
|  | 307         this.displays_view_.appendChild(div); | 
|  | 308       } | 
|  | 309     }, | 
|  | 310 | 
|  | 311     /** | 
|  | 312      * Called when the display arrangement has changed. | 
|  | 313      * @private | 
|  | 314      * @param {boolean} mirroring Whether current mode is mirroring or not. | 
|  | 315      * @param {Array} displays The list of the display information. | 
|  | 316      * @param {SecondaryDisplayLayout} layout The layout strategy. | 
|  | 317      */ | 
|  | 318     onDisplayChanged_: function(mirroring, displays, layout) { | 
|  | 319       this.mirroring_ = mirroring; | 
|  | 320       this.layout_ = layout; | 
|  | 321 | 
|  | 322       $('display-options-toggle-mirroring').textContent = | 
|  | 323           loadTimeData.getString( | 
|  | 324               this.mirroring_ ? 'stopMirroring' : 'startMirroring'); | 
|  | 325 | 
|  | 326       // Focus to the first display next to the primary one when |displays| list | 
|  | 327       // is updated. | 
|  | 328       if (this.displays_.length != displays.length) | 
|  | 329         this.focused_index_ = 1; | 
|  | 330 | 
|  | 331       this.displays_ = displays; | 
|  | 332 | 
|  | 333       if (this.displays_.length <= 1) | 
|  | 334         return; | 
|  | 335 | 
|  | 336       this.resetDisplaysView_(); | 
|  | 337       if (this.mirroring_) | 
|  | 338         this.layoutMirroringDisplays_(); | 
|  | 339       else | 
|  | 340         this.layoutDisplays_(); | 
|  | 341     }, | 
|  | 342   }; | 
|  | 343 | 
|  | 344   DisplayOptions.setDisplayInfo = function(mirroring, displays, layout) { | 
|  | 345     DisplayOptions.getInstance().onDisplayChanged_(mirroring, displays, layout); | 
|  | 346   }; | 
|  | 347 | 
|  | 348   // Export | 
|  | 349   return { | 
|  | 350     DisplayOptions: DisplayOptions | 
|  | 351   }; | 
|  | 352 }); | 
| OLD | NEW | 
|---|