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); | |
xiyuan
2012/10/22 19:54:44
Should we use element.offsetParent instead?
Also
Jun Mukai
2012/10/22 22:35:30
Done.
| |
64 point.x += element.offsetLeft; | |
65 point.y += element.offsetTop; | |
66 point.width = element.offsetWidth; | |
67 point.height = element.offsetHeight; | |
68 return point; | |
xiyuan
2012/10/22 19:54:44
nit: How about
return {
x: point.x + element
Jun Mukai
2012/10/22 22:35:30
Changed the code not to use recursion, so the code
| |
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() { | |
xiyuan
2012/10/22 19:54:44
nit: js method should start with lower case.
Fin
Jun Mukai
2012/10/22 22:35:30
Done.
| |
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() { | |
xiyuan
2012/10/22 19:54:44
nit: Clear -> clear
Jun Mukai
2012/10/22 22:35:30
Done.
| |
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) { | |
xiyuan
2012/10/22 19:54:44
This does not match what the comment above says. S
Jun Mukai
2012/10/22 22:35:30
The code is correct, my intention is that this.ove
| |
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 |