 Chromium Code Reviews
 Chromium Code Reviews Issue 10544171:
  Add OptionsUI and its handler for multiple displays.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 10544171:
  Add OptionsUI and its handler for multiple displays.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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 | |
| 
James Hawkins
2012/06/18 15:13:49
Remove blank line.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 7 var OptionsPage = options.OptionsPage; | |
| 8 | |
| 9 // The scale ratio of the display rectangle to its original size. | |
| 10 var VISUAL_SCALE = 1 / 10; | |
| 
James Hawkins
2012/06/18 15:13:49
/** const */
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 11 | |
| 12 /** | |
| 13 * Enumeration of secondary display layout. THe value has to be same as the | |
| 
James Hawkins
2012/06/18 15:13:49
s/THe/ The/
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 14 * values in ash/monitor/monitor_controller.cc. | |
| 15 * @enum {number} | |
| 16 */ | |
| 17 var SecondaryDisplayLayout = { | |
| 18 TOP: 0, | |
| 19 RIGHT: 1, | |
| 20 BOTTOM: 2, | |
| 21 LEFT: 3 | |
| 22 }; | |
| 23 | |
| 24 /** | |
| 25 * Encapsulated handling of the 'Display' page. | |
| 26 * @constructor | |
| 27 */ | |
| 28 function DisplayOptions() { | |
| 29 OptionsPage.call(this, | |
| 
James Hawkins
2012/06/18 15:13:49
Collapse parameters to save lines.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 30 'display', | |
| 31 loadTimeData.getString('displayOptionsPageTabTitle'), | |
| 32 'display-options'); | |
| 33 this.mirroring_ = false; | |
| 34 this.focused_index_ = null; | |
| 35 this.displays_ = []; | |
| 36 } | |
| 37 | |
| 38 cr.addSingletonGetter(DisplayOptions); | |
| 39 | |
| 40 DisplayOptions.prototype = { | |
| 41 __proto__: OptionsPage.prototype, | |
| 42 | |
| 43 /** | |
| 44 * Initialize the page. | |
| 45 */ | |
| 46 initializePage: function() { | |
| 47 var self = this; | |
| 
James Hawkins
2012/06/18 15:13:49
Use bind instead of var self.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 48 | |
| 49 OptionsPage.prototype.initializePage.call(this); | |
| 50 | |
| 51 $('display-options-confirm').onclick = function() { | |
| 52 OptionsPage.closeOverlay(); | |
| 53 }; | |
| 54 | |
| 55 $('display-options-toggle-mirroring').onclick = function() { | |
| 56 self.mirroring_ = !self.mirroring_; | |
| 57 chrome.send('setMirroring', [self.mirroring_]); | |
| 58 }; | |
| 59 | |
| 60 chrome.send('getDisplayInfo'); | |
| 61 }, | |
| 62 | |
| 63 /** | |
| 64 * Mouse move handler for dragging display rectangle. | |
| 65 * @private | |
| 66 * @param {Event} e The mouse move event. | |
| 67 */ | |
| 68 onMouseMove_: function(e) { | |
| 69 if (!this.dragging_) | |
| 70 return true; | |
| 71 | |
| 72 var index = -1; | |
| 73 for (var i = 0; i < this.displays_.length; i++) { | |
| 74 if (this.displays_[i] == this.dragging_.display) { | |
| 75 index = i; | |
| 76 break; | |
| 77 } | |
| 78 } | |
| 79 if (index < 0) | |
| 80 return true; | |
| 81 | |
| 82 // Note that current code of moving display-rectangles doesn't work | |
| 83 // if there are >=3 displays. This is our assumption for M21. | |
| 84 // TODO(mukai): Fix the code to allow >=3 displays. | |
| 85 var mouse_position = { | |
| 86 x: e.pageX - this.dragging_.offset.x, | |
| 87 y: e.pageY - this.dragging_.offset.y | |
| 88 }; | |
| 89 var new_position = { | |
| 90 x: mouse_position.x - this.dragging_.click_location.x, | |
| 91 y: mouse_position.y - this.dragging_.click_location.y | |
| 92 }; | |
| 93 | |
| 94 var primary_div = this.displays_[0].div; | |
| 95 var display = this.dragging_.display; | |
| 96 | |
| 97 // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of | |
| 98 // the primary display, and decide which area the display should reside. | |
| 99 var diagonal_slope = primary_div.offsetHeight / primary_div.offsetWidth; | |
| 100 var top_down_intercept = | |
| 101 primary_div.offsetTop - primary_div.offsetLeft * diagonal_slope; | |
| 
James Hawkins
2012/06/18 15:13:49
Indentation is off by two.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 102 var bottom_up_intercept = primary_div.offsetTop + | |
| 103 primary_div.offsetHeight + primary_div.offsetLeft * diagonal_slope; | |
| 
James Hawkins
2012/06/18 15:13:49
Indentation is off by two.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 104 | |
| 105 if (mouse_position.y > | |
| 106 top_down_intercept + mouse_position.x * diagonal_slope) { | |
| 107 if (mouse_position.y > | |
| 108 bottom_up_intercept - mouse_position.x * diagonal_slope) | |
| 109 this.layout_ = SecondaryDisplayLayout.BOTTOM; | |
| 110 else | |
| 111 this.layout_ = SecondaryDisplayLayout.LEFT; | |
| 112 } else { | |
| 113 if (mouse_position.y > | |
| 114 bottom_up_intercept - mouse_position.x * diagonal_slope) | |
| 115 this.layout_ = SecondaryDisplayLayout.RIGHT; | |
| 116 else | |
| 117 this.layout_ = SecondaryDisplayLayout.TOP; | |
| 118 } | |
| 119 | |
| 120 if (this.layout_ == SecondaryDisplayLayout.LEFT || | |
| 121 this.layout_ == SecondaryDisplayLayout.RIGHT) { | |
| 122 if (new_position.y > primary_div.offsetTop + primary_div.offsetHeight) | |
| 123 this.layout_ = SecondaryDisplayLayout.BOTTOM; | |
| 124 else if (new_position.y + display.div.offsetHeight < | |
| 125 primary_div.offsetTop) | |
| 126 this.layout_ = SecondaryDisplayLayout.TOP; | |
| 127 } else { | |
| 128 if (new_position.y > primary_div.offsetLeft + primary_div.offsetWidth) | |
| 129 this.layout_ = SecondaryDisplayLayout.RIGHT; | |
| 130 else if (new_position.y + display.div.offsetWidth < | |
| 131 primary_div.offstLeft) | |
| 132 this.layout_ = SecondaryDisplayLayout.LEFT; | |
| 133 } | |
| 134 | |
| 135 switch (this.layout_) { | |
| 136 case SecondaryDisplayLayout.RIGHT: | |
| 
James Hawkins
2012/06/18 15:13:49
Indentation is off by two.
 
Jun Mukai
2012/06/19 08:37:44
you mean the assignment below?  fixed those lines.
 | |
| 137 display.div.style.left = | |
| 138 primary_div.offsetLeft + primary_div.offsetWidth + 'px'; | |
| 139 display.div.style.top = new_position.y + 'px'; | |
| 140 break; | |
| 141 case SecondaryDisplayLayout.LEFT: | |
| 142 display.div.style.left = | |
| 143 primary_div.offsetLeft - display.div.offsetWidth + 'px'; | |
| 144 display.div.style.top = new_position.y + 'px'; | |
| 145 break; | |
| 146 case SecondaryDisplayLayout.TOP: | |
| 147 display.div.style.top = | |
| 148 primary_div.offsetTop - display.div.offsetHeight + 'px'; | |
| 149 display.div.style.left = new_position.x + 'px'; | |
| 150 break; | |
| 151 case SecondaryDisplayLayout.BOTTOM: | |
| 152 display.div.style.top = | |
| 153 primary_div.offsetTop + primary_div.offsetHeight + 'px'; | |
| 154 display.div.style.left = new_position.x + 'px'; | |
| 155 break; | |
| 156 } | |
| 157 | |
| 158 return false; | |
| 159 }, | |
| 160 | |
| 161 /** | |
| 162 * Mouse down handler for dragging display rectangle. | |
| 163 * @private | |
| 164 * @param {Event} e The mouse down event. | |
| 165 */ | |
| 166 onMouseDown_: function(e) { | |
| 167 if (this.mirroring_) | |
| 168 return true; | |
| 169 | |
| 170 if (e.button != 0) | |
| 171 return true; | |
| 172 | |
| 173 if (e.target == this.displays_view_) | |
| 174 return true; | |
| 175 | |
| 176 for (var i = 0; i < this.displays_.length; i++) { | |
| 177 var display = this.displays_[i]; | |
| 178 if (display.div == e.target) { | |
| 179 // Do not drag the primary monitor. | |
| 180 if (i == 0) | |
| 181 return true; | |
| 182 | |
| 183 this.focused_index_ = i; | |
| 184 this.dragging_ = { | |
| 185 display: display, | |
| 186 click_location: {x: e.offsetX, y: e.offsetY}, | |
| 187 offset: {x: e.pageX - e.offsetX - display.div.offsetLeft, | |
| 188 y: e.pageY - e.offsetY - display.div.offsetTop} | |
| 189 }; | |
| 190 if (display.div.className.indexOf('displays-focused') == -1) | |
| 191 display.div.className += ' displays-focused'; | |
| 192 } else if (display.div.className.indexOf('displays-focused') >= 0) { | |
| 193 // We can assume that '-primary' monitor doesn't have '-focused'. | |
| 194 this.displays_[i].div.className = 'displays-display'; | |
| 195 } | |
| 196 } | |
| 197 return false; | |
| 198 }, | |
| 199 | |
| 200 /** | |
| 201 * Mouse up handler for dragging display rectangle. | |
| 202 * @private | |
| 203 * @param {Event} e The mouse up event. | |
| 204 */ | |
| 205 onMouseUp_: function(e) { | |
| 206 if (this.dragging_) { | |
| 207 this.dragging_ = null; | |
| 208 chrome.send('setDisplayLayout', [this.layout_]); | |
| 209 } | |
| 210 return false; | |
| 211 }, | |
| 212 | |
| 213 resetDisplaysView_: function() { | |
| 
James Hawkins
2012/06/18 15:13:49
Document method.
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 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 * Layouts 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_. | |
| 
James Hawkins
2012/06/18 15:13:49
s/Layouts/Lays out/
 
Jun Mukai
2012/06/19 08:37:44
Done.
 | |
| 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_ ? 'stop-mirroring' : 'start-mirroring'); | |
| 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 |