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.define('options', function() { | 5 cr.define('options', function() { |
6 var OptionsPage = options.OptionsPage; | 6 var OptionsPage = options.OptionsPage; |
7 | 7 |
8 // The scale ratio of the display rectangle to its original size. | 8 // The scale ratio of the display rectangle to its original size. |
9 /** @const */ var VISUAL_SCALE = 1 / 10; | 9 /** @const */ var VISUAL_SCALE = 1 / 10; |
10 | 10 |
11 // The number of pixels to share the edges between displays. | 11 // The number of pixels to share the edges between displays. |
12 /** @const */ var MIN_OFFSET_OVERLAP = 5; | 12 /** @const */ var MIN_OFFSET_OVERLAP = 5; |
13 | 13 |
| 14 // The border width of the display rectangles for the focused one. |
| 15 /** @const */ var FOCUSED_BORDER_WIDTH_PX = 2; |
| 16 // The border width of the display rectangles for the normal one. |
| 17 /** @const */ var NORMAL_BORDER_WIDTH_PX = 1; |
| 18 |
| 19 // The constant values for the overscan calibration settings. |
| 20 // The height of an arrow. |
| 21 /** @const */ var ARROW_SIZE_PX = 10; |
| 22 |
| 23 // The gap from the boundary of the display rectangle and the arrow. |
| 24 /** @const */ var ARROW_GAP_PX = 2; |
| 25 |
| 26 // The margin size to handle events outside the target display. |
| 27 /** @const */ var ARROW_CONTAINER_MARGIN_PX = ARROW_SIZE_PX * 3; |
| 28 |
| 29 // The interval times to update the overscan while the user keeps pressing |
| 30 // the mouse button or touching. |
| 31 /** @const */ var OVERSCAN_TIC_INTERVAL_MS = 100; |
| 32 |
14 /** | 33 /** |
15 * Enumeration of secondary display layout. The value has to be same as the | 34 * Enumeration of secondary display layout. The value has to be same as the |
16 * values in ash/display/display_controller.cc. | 35 * values in ash/display/display_controller.cc. |
17 * @enum {number} | 36 * @enum {number} |
18 */ | 37 */ |
19 var SecondaryDisplayLayout = { | 38 var SecondaryDisplayLayout = { |
20 TOP: 0, | 39 TOP: 0, |
21 RIGHT: 1, | 40 RIGHT: 1, |
22 BOTTOM: 2, | 41 BOTTOM: 2, |
23 LEFT: 3 | 42 LEFT: 3 |
24 }; | 43 }; |
25 | 44 |
26 /** | 45 /** |
| 46 * Enumeration of the direction for the calibrating overscan settings. |
| 47 * @enum {number} |
| 48 */ |
| 49 var CalibrationDirection = { |
| 50 INNER: 1, |
| 51 OUTER: -1 |
| 52 }; |
| 53 |
| 54 /** |
| 55 * Calculates the bounds of |element| relative to the page. |
| 56 * @param {HTMLElement} element The element to be known. |
| 57 * @return {Object} The object for the bounds, with x, y, width, and height. |
| 58 */ |
| 59 function getBoundsInPage(element) { |
| 60 var bounds = { |
| 61 x: element.offsetLeft, |
| 62 y: element.offsetTop, |
| 63 width: element.offsetWidth, |
| 64 height: element.offsetHeight |
| 65 }; |
| 66 var parent = element.offsetParent; |
| 67 while (parent && parent != document.body) { |
| 68 bounds.x += parent.offsetLeft; |
| 69 bounds.y += parent.offsetTop; |
| 70 parent = parent.offsetParent; |
| 71 } |
| 72 return bounds; |
| 73 } |
| 74 |
| 75 /** |
| 76 * Gets the position of |point| to |rect|, left, right, top, or bottom. |
| 77 * @param {Object} rect The base rectangle with x, y, width, and height. |
| 78 * @param {Object} point The point to check the position. |
| 79 * @return {SecondaryDisplayLayout} The position of the calculated point. |
| 80 */ |
| 81 function getPositionToRectangle(rect, point) { |
| 82 // Separates the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of |
| 83 // the rect, and decides which area the display should reside. |
| 84 var diagonalSlope = rect.height / rect.width; |
| 85 var topDownIntercept = rect.y - rect.x * diagonalSlope; |
| 86 var bottomUpIntercept = rect.y + rect.height + rect.x * diagonalSlope; |
| 87 |
| 88 if (point.y > topDownIntercept + point.x * diagonalSlope) { |
| 89 if (point.y > bottomUpIntercept - point.x * diagonalSlope) |
| 90 return SecondaryDisplayLayout.BOTTOM; |
| 91 else |
| 92 return SecondaryDisplayLayout.LEFT; |
| 93 } else { |
| 94 if (point.y > bottomUpIntercept - point.x * diagonalSlope) |
| 95 return SecondaryDisplayLayout.RIGHT; |
| 96 else |
| 97 return SecondaryDisplayLayout.TOP; |
| 98 } |
| 99 } |
| 100 |
| 101 /** |
| 102 * DisplayOverscanCalibrator shows the arrows to calibrate overscan settings |
| 103 * and handles events of the actual user control. |
| 104 * @param {Object} display The display object for the calibrating overscan. |
| 105 * @constructor |
| 106 */ |
| 107 function DisplayOverscanCalibrator(display) { |
| 108 // Creates the calibration arrows over |display|. To achieve the UI, |
| 109 // a transparent container holds the arrows and handles events. |
| 110 this.container_ = document.createElement('div'); |
| 111 this.container_.id = 'display-overscan-calibration-arrow-container'; |
| 112 var containerSize = { |
| 113 width: display.div.offsetWidth + ARROW_CONTAINER_MARGIN_PX * 2, |
| 114 height: display.div.offsetHeight + ARROW_CONTAINER_MARGIN_PX * 2 |
| 115 }; |
| 116 this.container_.style.width = containerSize.width + 'px'; |
| 117 this.container_.style.height = containerSize.height + 'px'; |
| 118 this.container_.style.left = |
| 119 display.div.offsetLeft - ARROW_CONTAINER_MARGIN_PX + 'px'; |
| 120 this.container_.style.top = |
| 121 display.div.offsetTop - ARROW_CONTAINER_MARGIN_PX + 'px'; |
| 122 this.container_.onmousedown = this.onMouseDown_.bind(this); |
| 123 this.container_.onmouseup = this.onOperationEnd_.bind(this); |
| 124 this.container_.ontouchstart = this.onTouchStart_.bind(this); |
| 125 this.container_.ontouchend = this.onOperationEnd_.bind(this); |
| 126 |
| 127 // Creates arrows for each direction. |
| 128 var topArrow = this.createVerticalArrows_(); |
| 129 topArrow.style.left = containerSize.width / 2 - ARROW_SIZE_PX + 'px'; |
| 130 topArrow.style.top = ARROW_CONTAINER_MARGIN_PX - |
| 131 ARROW_SIZE_PX - ARROW_GAP_PX + 'px'; |
| 132 this.container_.appendChild(topArrow); |
| 133 var bottomArrow = this.createVerticalArrows_(); |
| 134 bottomArrow.style.left = containerSize.width / 2 - ARROW_SIZE_PX + 'px'; |
| 135 bottomArrow.style.bottom = ARROW_CONTAINER_MARGIN_PX - |
| 136 ARROW_SIZE_PX - ARROW_GAP_PX + 'px'; |
| 137 this.container_.appendChild(bottomArrow); |
| 138 var leftArrow = this.createHorizontalArrows_(); |
| 139 leftArrow.style.left = ARROW_CONTAINER_MARGIN_PX - |
| 140 ARROW_SIZE_PX - ARROW_GAP_PX + 'px'; |
| 141 leftArrow.style.top = containerSize.height / 2 - ARROW_SIZE_PX + 'px'; |
| 142 this.container_.appendChild(leftArrow); |
| 143 var rightArrow = this.createHorizontalArrows_(); |
| 144 rightArrow.style.right = ARROW_CONTAINER_MARGIN_PX - |
| 145 ARROW_SIZE_PX - ARROW_GAP_PX + 'px'; |
| 146 rightArrow.style.top = containerSize.height / 2 - ARROW_SIZE_PX + 'px'; |
| 147 this.container_.appendChild(rightArrow); |
| 148 |
| 149 display.div.parentNode.appendChild(this.container_); |
| 150 this.displayBounds_ = getBoundsInPage(display.div); |
| 151 this.overscan_ = display.overscan; |
| 152 chrome.send('startOverscanCalibration', [display.id]); |
| 153 }; |
| 154 |
| 155 DisplayOverscanCalibrator.prototype = { |
| 156 /** |
| 157 * The container of arrows. It also receives the user events. |
| 158 * @private |
| 159 */ |
| 160 container_: null, |
| 161 |
| 162 /** |
| 163 * The bounds of the display rectangle in the page. |
| 164 * @private |
| 165 */ |
| 166 displayBounds_: null, |
| 167 |
| 168 /** |
| 169 * The current overscan settins. |
| 170 * @private |
| 171 */ |
| 172 overscan_: null, |
| 173 |
| 174 /** |
| 175 * The location of the current user operation against the display. The |
| 176 * contents should be one of 'left', 'right', 'top', or 'bottom'. |
| 177 * @type {string} |
| 178 * @private |
| 179 */ |
| 180 location_: null, |
| 181 |
| 182 /** |
| 183 * The direction of the current user operation against the display. |
| 184 * @type {CalibrationDirection} |
| 185 * @private |
| 186 */ |
| 187 direction_: null, |
| 188 |
| 189 /** |
| 190 * The ID for the periodic timer to tic the calibration settings while the |
| 191 * user keeps pressing the mouse button. |
| 192 * @type {number} |
| 193 * @private |
| 194 */ |
| 195 timer_: null, |
| 196 |
| 197 /** |
| 198 * Called when everything is finished. |
| 199 */ |
| 200 finish: function() { |
| 201 this.container_.parentNode.removeChild(this.container_); |
| 202 chrome.send('finishOverscanCalibration'); |
| 203 }, |
| 204 |
| 205 /** |
| 206 * Called when every settings are cleared. |
| 207 */ |
| 208 clear: function() { |
| 209 chrome.send('clearOverscanCalibration'); |
| 210 }, |
| 211 |
| 212 /** |
| 213 * Mouse down event handler for overscan calibration. |
| 214 * @param {Event} e The mouse down event. |
| 215 * @private |
| 216 */ |
| 217 onMouseDown_: function(e) { |
| 218 e.preventDefault(); |
| 219 this.setupOverscanCalibration_(e); |
| 220 }, |
| 221 |
| 222 /** |
| 223 * Touch start event handler for overscan calibration. |
| 224 * @param {Event} e The touch start event. |
| 225 * @private |
| 226 */ |
| 227 onTouchStart_: function(e) { |
| 228 if (e.touches.length != 1) |
| 229 return; |
| 230 |
| 231 e.preventDefault(); |
| 232 var touch = e.touches[0]; |
| 233 this.setupOverscanCalibration_(e.touches[0]); |
| 234 }, |
| 235 |
| 236 /** |
| 237 * Event handler for ending the user operation of overscan calibration. |
| 238 * @param {Event} e The event object, mouse up event or touch end event. |
| 239 * @private |
| 240 */ |
| 241 onOperationEnd_: function(e) { |
| 242 if (this.timer_) { |
| 243 window.clearInterval(this.timer_); |
| 244 this.timer_ = null; |
| 245 e.preventDefault(); |
| 246 } |
| 247 }, |
| 248 |
| 249 /** |
| 250 * Sets up a new overscan calibration operation. It calculates the event |
| 251 * location and determines the contents of location. It also sets up a |
| 252 * timer to change the overscan settings continuously as far as the user |
| 253 * keeps pressing the mouse button or touching. The timer will be cleared |
| 254 * on ending the operation. |
| 255 * @param {Object} e The object to contain the location of the event with |
| 256 * pageX and pageY attributes. |
| 257 * @private |
| 258 */ |
| 259 setupOverscanCalibration_: function(e) { |
| 260 switch (getPositionToRectangle( |
| 261 this.displayBounds_, {x: e.pageX, y: e.pageY})) { |
| 262 case SecondaryDisplayLayout.RIGHT: |
| 263 this.location_ = 'right'; |
| 264 if (e.pageX < this.displayBounds_.x + this.displayBounds_.width) |
| 265 this.direction_ = CalibrationDirection.INNER; |
| 266 else |
| 267 this.direction_ = CalibrationDirection.OUTER; |
| 268 break; |
| 269 case SecondaryDisplayLayout.LEFT: |
| 270 this.location_ = 'left'; |
| 271 if (e.pageX > this.displayBounds_.x) |
| 272 this.direction_ = CalibrationDirection.INNER; |
| 273 else |
| 274 this.direction_ = CalibrationDirection.OUTER; |
| 275 break; |
| 276 case SecondaryDisplayLayout.TOP: |
| 277 this.location_ = 'top'; |
| 278 if (e.pageY > this.displayBounds_.y) |
| 279 this.direction_ = CalibrationDirection.INNER; |
| 280 else |
| 281 this.direction_ = CalibrationDirection.OUTER; |
| 282 break; |
| 283 case SecondaryDisplayLayout.BOTTOM: |
| 284 this.location_ = 'bottom'; |
| 285 if (e.pageY < this.displayBounds_.y + this.displayBounds_.height) { |
| 286 this.direction_ = CalibrationDirection.INNER; |
| 287 } else { |
| 288 this.direction_ = CalibrationDirection.OUTER; |
| 289 } |
| 290 break; |
| 291 } |
| 292 |
| 293 this.ticOverscanSize_(); |
| 294 this.timer_ = window.setInterval( |
| 295 this.ticOverscanSize_.bind(this), OVERSCAN_TIC_INTERVAL_MS); |
| 296 }, |
| 297 |
| 298 /** |
| 299 * Modifies the current overscans actually and sends the update to the |
| 300 * system. |
| 301 * @private |
| 302 */ |
| 303 ticOverscanSize_: function() { |
| 304 // Ignore the operation which causes some of overscan insets negative. |
| 305 if (this.direction_ == CalibrationDirection.OUTER && |
| 306 this.overscan_[this.location_] == 0) { |
| 307 return; |
| 308 } |
| 309 |
| 310 this.overscan_[this.location_] += this.direction_; |
| 311 chrome.send('updateOverscanCalibration', |
| 312 [this.overscan_.top, this.overscan_.left, |
| 313 this.overscan_.bottom, this.overscan_.right]); |
| 314 }, |
| 315 |
| 316 /** |
| 317 * Creates the arrows vertically aligned, for the calibration UI at the top |
| 318 * and bottom of the target display. |
| 319 * @return {HTMLElement} The created div which contains the arrows. |
| 320 * @private |
| 321 */ |
| 322 createVerticalArrows_: function() { |
| 323 var container = document.createElement('div'); |
| 324 container.style.width = ARROW_SIZE_PX * 2 + 'px'; |
| 325 container.style.height = |
| 326 ARROW_SIZE_PX * 2 + ARROW_GAP_PX * 2 + FOCUSED_BORDER_WIDTH_PX + 'px'; |
| 327 container.style.position = 'absolute'; |
| 328 |
| 329 var arrowUp = document.createElement('div'); |
| 330 arrowUp.className = 'display-overscan-calibration-arrow ' + |
| 331 'display-overscan-arrow-to-top'; |
| 332 arrowUp.style.left = '0'; |
| 333 arrowUp.style.top = -ARROW_SIZE_PX + 'px'; |
| 334 container.appendChild(arrowUp); |
| 335 var arrowDown = document.createElement('div'); |
| 336 arrowDown.className = 'display-overscan-calibration-arrow ' + |
| 337 'display-overscan-arrow-to-bottom'; |
| 338 arrowDown.style.left = '0'; |
| 339 arrowDown.style.bottom = -ARROW_SIZE_PX + 'px'; |
| 340 container.appendChild(arrowDown); |
| 341 return container; |
| 342 }, |
| 343 |
| 344 /** |
| 345 * Creates the arrows horizontally aligned, for the calibration UI at the |
| 346 * left and right of the target display. |
| 347 * @return {HTMLElement} The created div which contains the arrows. |
| 348 * @private |
| 349 */ |
| 350 createHorizontalArrows_: function() { |
| 351 var container = document.createElement('div'); |
| 352 container.style.width = |
| 353 ARROW_SIZE_PX * 2 + ARROW_GAP_PX * 2 + FOCUSED_BORDER_WIDTH_PX + 'px'; |
| 354 container.style.height = ARROW_SIZE_PX * 2 + 'px'; |
| 355 container.style.position = 'absolute'; |
| 356 |
| 357 var arrowLeft = document.createElement('div'); |
| 358 arrowLeft.className = 'display-overscan-calibration-arrow ' + |
| 359 'display-overscan-arrow-to-left'; |
| 360 arrowLeft.style.left = -ARROW_SIZE_PX + 'px'; |
| 361 arrowLeft.style.top = '0'; |
| 362 container.appendChild(arrowLeft); |
| 363 var arrowRight = document.createElement('div'); |
| 364 arrowRight.className = 'display-overscan-calibration-arrow ' + |
| 365 'display-overscan-arrow-to-right'; |
| 366 arrowRight.style.right = -ARROW_SIZE_PX + 'px'; |
| 367 arrowRight.style.top = '0'; |
| 368 container.appendChild(arrowRight); |
| 369 return container; |
| 370 } |
| 371 }; |
| 372 |
| 373 /** |
27 * Encapsulated handling of the 'Display' page. | 374 * Encapsulated handling of the 'Display' page. |
28 * @constructor | 375 * @constructor |
29 */ | 376 */ |
30 function DisplayOptions() { | 377 function DisplayOptions() { |
31 OptionsPage.call(this, 'display', | 378 OptionsPage.call(this, 'display', |
32 loadTimeData.getString('displayOptionsPageTabTitle'), | 379 loadTimeData.getString('displayOptionsPageTabTitle'), |
33 'display-options-page'); | 380 'display-options-page'); |
34 } | 381 } |
35 | 382 |
36 cr.addSingletonGetter(DisplayOptions); | 383 cr.addSingletonGetter(DisplayOptions); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 var container = $('display-options-displays-view-host'); | 465 var container = $('display-options-displays-view-host'); |
119 container.onmousemove = this.onMouseMove_.bind(this); | 466 container.onmousemove = this.onMouseMove_.bind(this); |
120 container.onmouseup = this.endDragging_.bind(this); | 467 container.onmouseup = this.endDragging_.bind(this); |
121 container.ontouchmove = this.onTouchMove_.bind(this); | 468 container.ontouchmove = this.onTouchMove_.bind(this); |
122 container.ontouchend = this.endDragging_.bind(this); | 469 container.ontouchend = this.endDragging_.bind(this); |
123 | 470 |
124 $('display-options-set-primary').onclick = (function() { | 471 $('display-options-set-primary').onclick = (function() { |
125 chrome.send('setPrimary', [this.displays_[this.focusedIndex_].id]); | 472 chrome.send('setPrimary', [this.displays_[this.focusedIndex_].id]); |
126 }).bind(this); | 473 }).bind(this); |
127 | 474 |
| 475 $('selected-display-start-calibrating-overscan').onclick = (function() { |
| 476 this.overscanCalibrator_ = new DisplayOverscanCalibrator( |
| 477 this.displays_[this.focusedIndex_]); |
| 478 this.updateSelectedDisplayDescription_(); |
| 479 }).bind(this); |
| 480 $('selected-display-finish-calibrating-overscan').onclick = (function() { |
| 481 this.overscanCalibrator_.finish(); |
| 482 this.overscanCalibrator_ = null; |
| 483 this.updateSelectedDisplayDescription_(); |
| 484 }).bind(this); |
| 485 $('selected-display-clear-calibrating-overscan').onclick = (function() { |
| 486 this.overscanCalibrator_.clear(); |
| 487 this.overscanCalibrator_ = null; |
| 488 this.updateSelectedDisplayDescription_(); |
| 489 }).bind(this); |
| 490 |
128 chrome.send('getDisplayInfo'); | 491 chrome.send('getDisplayInfo'); |
129 }, | 492 }, |
130 | 493 |
131 /** @override */ | 494 /** @override */ |
132 onVisibilityChanged_: function() { | 495 onVisibilityChanged_: function() { |
133 OptionsPage.prototype.onVisibilityChanged_(this); | 496 OptionsPage.prototype.onVisibilityChanged_(this); |
134 if (this.visible) | 497 if (this.visible) |
135 chrome.send('getDisplayInfo'); | 498 chrome.send('getDisplayInfo'); |
136 }, | 499 }, |
137 | 500 |
138 /** | 501 /** |
139 * Mouse move handler for dragging display rectangle. | 502 * Mouse move handler for dragging display rectangle. |
| 503 * @param {Event} e The mouse move event. |
140 * @private | 504 * @private |
141 * @param {Event} e The mouse move event. | |
142 */ | 505 */ |
143 onMouseMove_: function(e) { | 506 onMouseMove_: function(e) { |
144 return this.processDragging_(e, {x: e.pageX, y: e.pageY}); | 507 return this.processDragging_(e, {x: e.pageX, y: e.pageY}); |
145 }, | 508 }, |
146 | 509 |
147 /** | 510 /** |
148 * Touch move handler for dragging display rectangle. | 511 * Touch move handler for dragging display rectangle. |
| 512 * @param {Event} e The touch move event. |
149 * @private | 513 * @private |
150 * @param {Event} e The touch move event. | |
151 */ | 514 */ |
152 onTouchMove_: function(e) { | 515 onTouchMove_: function(e) { |
153 if (e.touches.length != 1) | 516 if (e.touches.length != 1) |
154 return true; | 517 return true; |
155 | 518 |
156 var touchLocation = {x: e.touches[0].pageX, y: e.touches[0].pageY}; | 519 var touchLocation = {x: e.touches[0].pageX, y: e.touches[0].pageY}; |
157 // Touch move events happen even if the touch location doesn't change, but | 520 // Touch move events happen even if the touch location doesn't change, but |
158 // it doesn't need to process the dragging. Since sometimes the touch | 521 // it doesn't need to process the dragging. Since sometimes the touch |
159 // position changes slightly even though the user doesn't think to move | 522 // position changes slightly even though the user doesn't think to move |
160 // the finger, very small move is just ignored. | 523 // the finger, very small move is just ignored. |
161 /** @const */ var IGNORABLE_TOUCH_MOVE_PX = 1; | 524 /** @const */ var IGNORABLE_TOUCH_MOVE_PX = 1; |
162 var x_diff = Math.abs(touchLocation.x - this.lastTouchLocation_.x); | 525 var x_diff = Math.abs(touchLocation.x - this.lastTouchLocation_.x); |
163 var y_diff = Math.abs(touchLocation.y - this.lastTouchLocation_.y); | 526 var y_diff = Math.abs(touchLocation.y - this.lastTouchLocation_.y); |
164 if (x_diff <= IGNORABLE_TOUCH_MOVE_PX && | 527 if (x_diff <= IGNORABLE_TOUCH_MOVE_PX && |
165 y_diff <= IGNORABLE_TOUCH_MOVE_PX) { | 528 y_diff <= IGNORABLE_TOUCH_MOVE_PX) { |
166 return true; | 529 return true; |
167 } | 530 } |
168 | 531 |
169 this.lastTouchLocation_ = touchLocation; | 532 this.lastTouchLocation_ = touchLocation; |
170 return this.processDragging_(e, touchLocation); | 533 return this.processDragging_(e, touchLocation); |
171 }, | 534 }, |
172 | 535 |
173 /** | 536 /** |
174 * Mouse down handler for dragging display rectangle. | 537 * Mouse down handler for dragging display rectangle. |
| 538 * @param {Event} e The mouse down event. |
175 * @private | 539 * @private |
176 * @param {Event} e The mouse down event. | |
177 */ | 540 */ |
178 onMouseDown_: function(e) { | 541 onMouseDown_: function(e) { |
179 if (this.mirroring_) | 542 if (this.mirroring_) |
180 return true; | 543 return true; |
181 | 544 |
182 if (e.button != 0) | 545 if (e.button != 0) |
183 return true; | 546 return true; |
184 | 547 |
185 e.preventDefault(); | 548 e.preventDefault(); |
186 return this.startDragging_(e.target, {x: e.pageX, y: e.pageY}); | 549 return this.startDragging_(e.target, {x: e.pageX, y: e.pageY}); |
187 }, | 550 }, |
188 | 551 |
189 /** | 552 /** |
190 * Touch start handler for dragging display rectangle. | 553 * Touch start handler for dragging display rectangle. |
| 554 * @param {Event} e The touch start event. |
191 * @private | 555 * @private |
192 * @param {Event} e The touch start event. | |
193 */ | 556 */ |
194 onTouchStart_: function(e) { | 557 onTouchStart_: function(e) { |
195 if (this.mirroring_) | 558 if (this.mirroring_) |
196 return true; | 559 return true; |
197 | 560 |
198 if (e.touches.length != 1) | 561 if (e.touches.length != 1) |
199 return false; | 562 return false; |
200 | 563 |
201 e.preventDefault(); | 564 e.preventDefault(); |
202 var touch = e.touches[0]; | 565 var touch = e.touches[0]; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) | 609 if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) |
247 return basePoint; | 610 return basePoint; |
248 else if (endDiff < SNAP_DISTANCE_PX) | 611 else if (endDiff < SNAP_DISTANCE_PX) |
249 return basePoint + baseWidth - width; | 612 return basePoint + baseWidth - width; |
250 | 613 |
251 return point; | 614 return point; |
252 }, | 615 }, |
253 | 616 |
254 /** | 617 /** |
255 * Processes the actual dragging of display rectangle. | 618 * Processes the actual dragging of display rectangle. |
256 * @private | |
257 * @param {Event} e The event which triggers this drag. | 619 * @param {Event} e The event which triggers this drag. |
258 * @param {Object} eventLocation The location where the event happens. | 620 * @param {Object} eventLocation The location where the event happens. |
| 621 * @private |
259 */ | 622 */ |
260 processDragging_: function(e, eventLocation) { | 623 processDragging_: function(e, eventLocation) { |
261 if (!this.dragging_) | 624 if (!this.dragging_) |
262 return true; | 625 return true; |
263 | 626 |
264 var index = -1; | 627 var index = -1; |
265 for (var i = 0; i < this.displays_.length; i++) { | 628 for (var i = 0; i < this.displays_.length; i++) { |
266 if (this.displays_[i] == this.dragging_.display) { | 629 if (this.displays_[i] == this.dragging_.display) { |
267 index = i; | 630 index = i; |
268 break; | 631 break; |
(...skipping 21 matching lines...) Expand all Loading... |
290 newPosition.x = this.snapToEdge_(newPosition.x, draggingDiv.offsetWidth, | 653 newPosition.x = this.snapToEdge_(newPosition.x, draggingDiv.offsetWidth, |
291 baseDiv.offsetLeft, baseDiv.offsetWidth); | 654 baseDiv.offsetLeft, baseDiv.offsetWidth); |
292 newPosition.y = this.snapToEdge_(newPosition.y, draggingDiv.offsetHeight, | 655 newPosition.y = this.snapToEdge_(newPosition.y, draggingDiv.offsetHeight, |
293 baseDiv.offsetTop, baseDiv.offsetHeight); | 656 baseDiv.offsetTop, baseDiv.offsetHeight); |
294 | 657 |
295 var newCenter = { | 658 var newCenter = { |
296 x: newPosition.x + draggingDiv.offsetWidth / 2, | 659 x: newPosition.x + draggingDiv.offsetWidth / 2, |
297 y: newPosition.y + draggingDiv.offsetHeight / 2 | 660 y: newPosition.y + draggingDiv.offsetHeight / 2 |
298 }; | 661 }; |
299 | 662 |
300 // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of | 663 var baseBounds = { |
301 // the base display, and decide which area the display should reside. | 664 x: baseDiv.offsetLeft, |
302 var diagonalSlope = baseDiv.offsetHeight / baseDiv.offsetWidth; | 665 y: baseDiv.offsetTop, |
303 var topDownIntercept = | 666 width: baseDiv.offsetWidth, |
304 baseDiv.offsetTop - baseDiv.offsetLeft * diagonalSlope; | 667 height: baseDiv.offsetHeight |
305 var bottomUpIntercept = baseDiv.offsetTop + | 668 }; |
306 baseDiv.offsetHeight + baseDiv.offsetLeft * diagonalSlope; | 669 switch (getPositionToRectangle(baseBounds, newCenter)) { |
307 | 670 case SecondaryDisplayLayout.RIGHT: |
308 if (newCenter.y > | 671 this.layout_ = this.dragging_.display.isPrimary ? |
309 topDownIntercept + newCenter.x * diagonalSlope) { | 672 SecondaryDisplayLayout.LEFT : SecondaryDisplayLayout.RIGHT; |
310 if (newCenter.y > | 673 break; |
311 bottomUpIntercept - newCenter.x * diagonalSlope) | 674 case SecondaryDisplayLayout.LEFT: |
312 this.layout_ = this.dragging_.display.isPrimary ? | 675 this.layout_ = this.dragging_.display.isPrimary ? |
313 SecondaryDisplayLayout.TOP : SecondaryDisplayLayout.BOTTOM; | 676 SecondaryDisplayLayout.RIGHT : SecondaryDisplayLayout.LEFT; |
314 else | 677 break; |
315 this.layout_ = this.dragging_.display.isPrimary ? | 678 case SecondaryDisplayLayout.TOP: |
316 SecondaryDisplayLayout.RIGHT : SecondaryDisplayLayout.LEFT; | 679 this.layout_ = this.dragging_.display.isPrimary ? |
317 } else { | 680 SecondaryDisplayLayout.BOTTOM : SecondaryDisplayLayout.TOP; |
318 if (newCenter.y > | 681 break; |
319 bottomUpIntercept - newCenter.x * diagonalSlope) | 682 case SecondaryDisplayLayout.BOTTOM: |
320 this.layout_ = this.dragging_.display.isPrimary ? | 683 this.layout_ = this.dragging_.display.isPrimary ? |
321 SecondaryDisplayLayout.LEFT : SecondaryDisplayLayout.RIGHT; | 684 SecondaryDisplayLayout.TOP : SecondaryDisplayLayout.BOTTOM; |
322 else | 685 break; |
323 this.layout_ = this.dragging_.display.isPrimary ? | |
324 SecondaryDisplayLayout.BOTTOM : SecondaryDisplayLayout.TOP; | |
325 } | 686 } |
326 | 687 |
327 if (this.layout_ == SecondaryDisplayLayout.LEFT || | 688 if (this.layout_ == SecondaryDisplayLayout.LEFT || |
328 this.layout_ == SecondaryDisplayLayout.RIGHT) { | 689 this.layout_ == SecondaryDisplayLayout.RIGHT) { |
329 if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) | 690 if (newPosition.y > baseDiv.offsetTop + baseDiv.offsetHeight) |
330 this.layout_ = this.dragging_.display.isPrimary ? | 691 this.layout_ = this.dragging_.display.isPrimary ? |
331 SecondaryDisplayLayout.TOP : SecondaryDisplayLayout.BOTTOM; | 692 SecondaryDisplayLayout.TOP : SecondaryDisplayLayout.BOTTOM; |
332 else if (newPosition.y + draggingDiv.offsetHeight < | 693 else if (newPosition.y + draggingDiv.offsetHeight < |
333 baseDiv.offsetTop) | 694 baseDiv.offsetTop) |
334 this.layout_ = this.dragging_.display.isPrimary ? | 695 this.layout_ = this.dragging_.display.isPrimary ? |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 draggingDiv.style.left = newPosition.x + 'px'; | 746 draggingDiv.style.left = newPosition.x + 'px'; |
386 break; | 747 break; |
387 } | 748 } |
388 | 749 |
389 this.dirty_ = true; | 750 this.dirty_ = true; |
390 return false; | 751 return false; |
391 }, | 752 }, |
392 | 753 |
393 /** | 754 /** |
394 * start dragging of a display rectangle. | 755 * start dragging of a display rectangle. |
395 * @private | |
396 * @param {HTMLElement} target The event target. | 756 * @param {HTMLElement} target The event target. |
397 * @param {Object} eventLocation The object to hold the location where | 757 * @param {Object} eventLocation The object to hold the location where |
398 * this event happens. | 758 * this event happens. |
| 759 * @private |
399 */ | 760 */ |
400 startDragging_: function(target, eventLocation) { | 761 startDragging_: function(target, eventLocation) { |
401 this.focusedIndex_ = null; | 762 this.focusedIndex_ = null; |
402 for (var i = 0; i < this.displays_.length; i++) { | 763 for (var i = 0; i < this.displays_.length; i++) { |
403 var display = this.displays_[i]; | 764 var display = this.displays_[i]; |
404 if (display.div == target || | 765 if (display.div == target || |
405 (display.isPrimary && $('display-launcher') == target)) { | 766 (display.isPrimary && $('display-launcher') == target)) { |
406 this.focusedIndex_ = i; | 767 this.focusedIndex_ = i; |
407 break; | 768 break; |
408 } | 769 } |
409 } | 770 } |
410 | 771 |
411 for (var i = 0; i < this.displays_.length; i++) { | 772 for (var i = 0; i < this.displays_.length; i++) { |
412 var display = this.displays_[i]; | 773 var display = this.displays_[i]; |
413 display.div.className = 'displays-display'; | 774 display.div.className = 'displays-display'; |
414 this.resizeDisplayRectangle_(display, i); | 775 this.resizeDisplayRectangle_(display, i); |
415 if (i != this.focusedIndex_) | 776 if (i != this.focusedIndex_) |
416 continue; | 777 continue; |
417 | 778 |
418 display.div.classList.add('displays-focused'); | 779 display.div.classList.add('displays-focused'); |
419 this.dragging_ = { | 780 this.dragging_ = { |
420 display: display, | 781 display: display, |
421 originalLocation: { | 782 originalLocation: { |
422 x: display.div.offsetLeft, y: display.div.offsetTop | 783 x: display.div.offsetLeft, y: display.div.offsetTop |
423 }, | 784 }, |
424 eventLocation: eventLocation | 785 eventLocation: eventLocation |
425 }; | 786 }; |
426 } | 787 } |
| 788 |
| 789 if (this.overscanCalibrator_) { |
| 790 this.overscanCalibrator_.finish(); |
| 791 this.overscanCalibrator_ = null; |
| 792 } |
427 this.updateSelectedDisplayDescription_(); | 793 this.updateSelectedDisplayDescription_(); |
428 return false; | 794 return false; |
429 }, | 795 }, |
430 | 796 |
431 /** | 797 /** |
432 * finish the current dragging of displays. | 798 * finish the current dragging of displays. |
| 799 * @param {Event} e The event which triggers this. |
433 * @private | 800 * @private |
434 * @param {Event} e The event which triggers this. | |
435 */ | 801 */ |
436 endDragging_: function(e) { | 802 endDragging_: function(e) { |
437 this.lastTouchLocation_ = null; | 803 this.lastTouchLocation_ = null; |
438 if (this.dragging_) { | 804 if (this.dragging_) { |
439 // Make sure the dragging location is connected. | 805 // Make sure the dragging location is connected. |
440 var baseDiv = this.dragging_.display.isPrimary ? | 806 var baseDiv = this.dragging_.display.isPrimary ? |
441 this.secondaryDisplay_.div : this.primaryDisplay_.div; | 807 this.secondaryDisplay_.div : this.primaryDisplay_.div; |
442 var draggingDiv = this.dragging_.display.div; | 808 var draggingDiv = this.dragging_.display.div; |
443 if (this.layout_ == SecondaryDisplayLayout.LEFT || | 809 if (this.layout_ == SecondaryDisplayLayout.LEFT || |
444 this.layout_ == SecondaryDisplayLayout.RIGHT) { | 810 this.layout_ == SecondaryDisplayLayout.RIGHT) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 while (nameElement.childNodes.length > 0) | 851 while (nameElement.childNodes.length > 0) |
486 nameElement.removeChild(nameElement.firstChild); | 852 nameElement.removeChild(nameElement.firstChild); |
487 nameElement.appendChild(document.createTextNode(display.name)); | 853 nameElement.appendChild(document.createTextNode(display.name)); |
488 | 854 |
489 var resolutionData = display.width + 'x' + display.height; | 855 var resolutionData = display.width + 'x' + display.height; |
490 var resolutionElement = $('selected-display-resolution'); | 856 var resolutionElement = $('selected-display-resolution'); |
491 while (resolutionElement.childNodes.length > 0) | 857 while (resolutionElement.childNodes.length > 0) |
492 resolutionElement.removeChild(resolutionElement.firstChild); | 858 resolutionElement.removeChild(resolutionElement.firstChild); |
493 resolutionElement.appendChild(document.createTextNode(resolutionData)); | 859 resolutionElement.appendChild(document.createTextNode(resolutionData)); |
494 | 860 |
| 861 if (this.overscanCalibrator_) { |
| 862 $('start-calibrating-overscan-control').hidden = true; |
| 863 $('end-calibrating-overscan-control').hidden = false; |
| 864 } else { |
| 865 $('start-calibrating-overscan-control').hidden = false; |
| 866 $('end-calibrating-overscan-control').hidden = true; |
| 867 } |
| 868 |
495 var arrow = $('display-configuration-arrow'); | 869 var arrow = $('display-configuration-arrow'); |
496 arrow.hidden = false; | 870 arrow.hidden = false; |
497 arrow.style.top = | 871 arrow.style.top = |
498 $('display-configurations').offsetTop - arrow.offsetHeight / 2 + 'px'; | 872 $('display-configurations').offsetTop - arrow.offsetHeight / 2 + 'px'; |
499 arrow.style.left = display.div.offsetLeft + display.div.offsetWidth / 2 - | 873 arrow.style.left = display.div.offsetLeft + display.div.offsetWidth / 2 - |
500 arrow.offsetWidth / 2 + 'px'; | 874 arrow.offsetWidth / 2 + 'px'; |
501 | 875 |
502 $('display-options-set-primary').disabled = | 876 $('display-options-set-primary').disabled = |
503 this.displays_[this.focusedIndex_].isPrimary; | 877 this.displays_[this.focusedIndex_].isPrimary; |
504 }, | 878 }, |
(...skipping 11 matching lines...) Expand all Loading... |
516 }, | 890 }, |
517 | 891 |
518 /** | 892 /** |
519 * Resize the specified display rectangle to keep the change of | 893 * Resize the specified display rectangle to keep the change of |
520 * the border width. | 894 * the border width. |
521 * @param {Object} display The display object. | 895 * @param {Object} display The display object. |
522 * @param {number} index The index of the display. | 896 * @param {number} index The index of the display. |
523 * @private | 897 * @private |
524 */ | 898 */ |
525 resizeDisplayRectangle_: function(display, index) { | 899 resizeDisplayRectangle_: function(display, index) { |
526 /** @const */ var FOCUSED_BORDER_WIDTH_PX = 2; | |
527 /** @const */ var NORMAL_BORDER_WIDTH_PX = 1; | |
528 var borderWidth = (index == this.focusedIndex_) ? | 900 var borderWidth = (index == this.focusedIndex_) ? |
529 FOCUSED_BORDER_WIDTH_PX : NORMAL_BORDER_WIDTH_PX; | 901 FOCUSED_BORDER_WIDTH_PX : NORMAL_BORDER_WIDTH_PX; |
530 display.div.style.width = | 902 display.div.style.width = |
531 display.width * this.visualScale_ - borderWidth * 2 + 'px'; | 903 display.width * this.visualScale_ - borderWidth * 2 + 'px'; |
532 display.div.style.height = | 904 display.div.style.height = |
533 display.height * this.visualScale_ - borderWidth * 2 + 'px'; | 905 display.height * this.visualScale_ - borderWidth * 2 + 'px'; |
534 display.div.style.lineHeight = display.div.style.height; | 906 display.div.style.lineHeight = display.div.style.height; |
535 if (display.isPrimary) { | 907 if (display.isPrimary) { |
536 var launcher = display.div.firstChild; | 908 var launcher = display.div.firstChild; |
537 if (launcher && launcher.id == 'display-launcher') { | 909 if (launcher && launcher.id == 'display-launcher') { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 | 1026 |
655 div.onmousedown = this.onMouseDown_.bind(this); | 1027 div.onmousedown = this.onMouseDown_.bind(this); |
656 div.ontouchstart = this.onTouchStart_.bind(this); | 1028 div.ontouchstart = this.onTouchStart_.bind(this); |
657 | 1029 |
658 this.displaysView_.appendChild(div); | 1030 this.displaysView_.appendChild(div); |
659 } | 1031 } |
660 }, | 1032 }, |
661 | 1033 |
662 /** | 1034 /** |
663 * Called when the display arrangement has changed. | 1035 * Called when the display arrangement has changed. |
664 * @private | |
665 * @param {boolean} mirroring Whether current mode is mirroring or not. | 1036 * @param {boolean} mirroring Whether current mode is mirroring or not. |
666 * @param {Array} displays The list of the display information. | 1037 * @param {Array} displays The list of the display information. |
667 * @param {SecondaryDisplayLayout} layout The layout strategy. | 1038 * @param {SecondaryDisplayLayout} layout The layout strategy. |
668 * @param {number} offset The offset of the secondary display. | 1039 * @param {number} offset The offset of the secondary display. |
| 1040 * @private |
669 */ | 1041 */ |
670 onDisplayChanged_: function(mirroring, displays, layout, offset) { | 1042 onDisplayChanged_: function(mirroring, displays, layout, offset) { |
671 this.mirroring_ = mirroring; | 1043 this.mirroring_ = mirroring; |
672 this.layout_ = layout; | 1044 this.layout_ = layout; |
673 this.offset_ = offset; | 1045 this.offset_ = offset; |
674 this.dirty_ = false; | 1046 this.dirty_ = false; |
675 | 1047 |
676 $('display-options-toggle-mirroring').textContent = | 1048 $('display-options-toggle-mirroring').textContent = |
677 loadTimeData.getString( | 1049 loadTimeData.getString( |
678 this.mirroring_ ? 'stopMirroring' : 'startMirroring'); | 1050 this.mirroring_ ? 'stopMirroring' : 'startMirroring'); |
679 | 1051 |
680 // Focus to the first display next to the primary one when |displays| list | 1052 // Focus to the first display next to the primary one when |displays| list |
681 // is updated. | 1053 // is updated. |
682 if (this.mirroring_) | 1054 if (this.mirroring_) |
683 this.focusedIndex_ = null; | 1055 this.focusedIndex_ = null; |
684 else if (this.displays_.length != displays.length) | 1056 else if (this.displays_.length != displays.length) |
685 this.focusedIndex_ = 1; | 1057 this.focusedIndex_ = 1; |
686 | 1058 |
687 this.displays_ = displays; | 1059 this.displays_ = displays; |
688 | 1060 |
689 this.resetDisplaysView_(); | 1061 this.resetDisplaysView_(); |
690 if (this.mirroring_) | 1062 if (this.mirroring_) |
691 this.layoutMirroringDisplays_(); | 1063 this.layoutMirroringDisplays_(); |
692 else | 1064 else |
693 this.layoutDisplays_(); | 1065 this.layoutDisplays_(); |
| 1066 |
| 1067 if (this.overscanCalibrator_) { |
| 1068 this.overscanCalibrator_.finish(); |
| 1069 this.overscanCalibrator_ = new DisplayOverscanCalibrator( |
| 1070 this.displays_[this.focusedIndex_]); |
| 1071 } |
694 this.updateSelectedDisplayDescription_(); | 1072 this.updateSelectedDisplayDescription_(); |
695 } | 1073 } |
696 }; | 1074 }; |
697 | 1075 |
698 DisplayOptions.setDisplayInfo = function( | 1076 DisplayOptions.setDisplayInfo = function( |
699 mirroring, displays, layout, offset) { | 1077 mirroring, displays, layout, offset) { |
700 DisplayOptions.getInstance().onDisplayChanged_( | 1078 DisplayOptions.getInstance().onDisplayChanged_( |
701 mirroring, displays, layout, offset); | 1079 mirroring, displays, layout, offset); |
702 }; | 1080 }; |
703 | 1081 |
704 // Export | 1082 // Export |
705 return { | 1083 return { |
706 DisplayOptions: DisplayOptions | 1084 DisplayOptions: DisplayOptions |
707 }; | 1085 }; |
708 }); | 1086 }); |
OLD | NEW |