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