Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(582)

Side by Side Diff: chrome/browser/resources/options/chromeos/display_options.js

Issue 11195036: Overscan calibration UI. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698