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

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

Issue 10809005: Options: Rename chrome/browser/resources/options2 -> chrome/browser/resources/options. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 8 years, 4 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 cr.define('options', function() {
6 var OptionsPage = options.OptionsPage;
7
8 // The scale ratio of the display rectangle to its original size.
9 /** @const */ var VISUAL_SCALE = 1 / 10;
10
11 // The number of pixels to share the edges between displays.
12 /** @const */ var MIN_OFFSET_OVERLAP = 5;
13
14 /**
15 * Enumeration of secondary display layout. The value has to be same as the
16 * values in ash/monitor/monitor_controller.cc.
17 * @enum {number}
18 */
19 var SecondaryDisplayLayout = {
20 TOP: 0,
21 RIGHT: 1,
22 BOTTOM: 2,
23 LEFT: 3
24 };
25
26 /**
27 * Encapsulated handling of the 'Display' page.
28 * @constructor
29 */
30 function DisplayOptions() {
31 OptionsPage.call(this, 'display',
32 loadTimeData.getString('displayOptionsPageTabTitle'),
33 'display-options');
34 this.mirroring_ = false;
35 this.focusedIndex_ = null;
36 this.displays_ = [];
37 }
38
39 cr.addSingletonGetter(DisplayOptions);
40
41 DisplayOptions.prototype = {
42 __proto__: OptionsPage.prototype,
43
44 /**
45 * Initialize the page.
46 */
47 initializePage: function() {
48 OptionsPage.prototype.initializePage.call(this);
49
50 $('display-options-toggle-mirroring').onclick = (function() {
51 this.mirroring_ = !this.mirroring_;
52 chrome.send('setMirroring', [this.mirroring_]);
53 }).bind(this);
54
55 $('display-options-apply').onclick = this.applyResult_.bind(this);
56 chrome.send('getDisplayInfo');
57 },
58
59 /** @override */
60 onVisibilityChanged_: function() {
61 OptionsPage.prototype.onVisibilityChanged_(this);
62 if (this.visible)
63 chrome.send('getDisplayInfo');
64 },
65
66 /**
67 * Collects the current data and sends it to Chrome.
68 * @private
69 */
70 applyResult_: function() {
71 // Offset is calculated from top or left edge.
72 var primary = this.displays_[0];
73 var secondary = this.displays_[1];
74 var offset;
75 if (this.layout_ == SecondaryDisplayLayout.LEFT ||
76 this.layout_ == SecondaryDisplayLayout.RIGHT) {
77 offset = secondary.div.offsetTop - primary.div.offsetTop;
78 } else {
79 offset = secondary.div.offsetLeft - primary.div.offsetLeft;
80 }
81 chrome.send('setDisplayLayout', [this.layout_, offset / VISUAL_SCALE]);
82 },
83
84 /**
85 * Mouse move handler for dragging display rectangle.
86 * @private
87 * @param {Event} e The mouse move event.
88 */
89 onMouseMove_: function(e) {
90 if (!this.dragging_)
91 return true;
92
93 var index = -1;
94 for (var i = 0; i < this.displays_.length; i++) {
95 if (this.displays_[i] == this.dragging_.display) {
96 index = i;
97 break;
98 }
99 }
100 if (index < 0)
101 return true;
102
103 // Note that current code of moving display-rectangles doesn't work
104 // if there are >=3 displays. This is our assumption for M21.
105 // TODO(mukai): Fix the code to allow >=3 displays.
106 var mousePosition = {
107 x: e.pageX - this.dragging_.offset.x,
108 y: e.pageY - this.dragging_.offset.y
109 };
110 var newPosition = {
111 x: mousePosition.x - this.dragging_.clickLocation.x,
112 y: mousePosition.y - this.dragging_.clickLocation.y
113 };
114
115 var primaryDiv = this.displays_[0].div;
116 var display = this.dragging_.display;
117
118 // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of
119 // the primary display, and decide which area the display should reside.
120 var diagonalSlope = primaryDiv.offsetHeight / primaryDiv.offsetWidth;
121 var topDownIntercept =
122 primaryDiv.offsetTop - primaryDiv.offsetLeft * diagonalSlope;
123 var bottomUpIntercept = primaryDiv.offsetTop +
124 primaryDiv.offsetHeight + primaryDiv.offsetLeft * diagonalSlope;
125
126 if (mousePosition.y >
127 topDownIntercept + mousePosition.x * diagonalSlope) {
128 if (mousePosition.y >
129 bottomUpIntercept - mousePosition.x * diagonalSlope)
130 this.layout_ = SecondaryDisplayLayout.BOTTOM;
131 else
132 this.layout_ = SecondaryDisplayLayout.LEFT;
133 } else {
134 if (mousePosition.y >
135 bottomUpIntercept - mousePosition.x * diagonalSlope)
136 this.layout_ = SecondaryDisplayLayout.RIGHT;
137 else
138 this.layout_ = SecondaryDisplayLayout.TOP;
139 }
140
141 if (this.layout_ == SecondaryDisplayLayout.LEFT ||
142 this.layout_ == SecondaryDisplayLayout.RIGHT) {
143 if (newPosition.y > primaryDiv.offsetTop + primaryDiv.offsetHeight)
144 this.layout_ = SecondaryDisplayLayout.BOTTOM;
145 else if (newPosition.y + display.div.offsetHeight <
146 primaryDiv.offsetTop)
147 this.layout_ = SecondaryDisplayLayout.TOP;
148 } else {
149 if (newPosition.y > primaryDiv.offsetLeft + primaryDiv.offsetWidth)
150 this.layout_ = SecondaryDisplayLayout.RIGHT;
151 else if (newPosition.y + display.div.offsetWidth <
152 primaryDiv.offstLeft)
153 this.layout_ = SecondaryDisplayLayout.LEFT;
154 }
155
156 switch (this.layout_) {
157 case SecondaryDisplayLayout.RIGHT:
158 display.div.style.left =
159 primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px';
160 display.div.style.top = newPosition.y + 'px';
161 break;
162 case SecondaryDisplayLayout.LEFT:
163 display.div.style.left =
164 primaryDiv.offsetLeft - display.div.offsetWidth + 'px';
165 display.div.style.top = newPosition.y + 'px';
166 break;
167 case SecondaryDisplayLayout.TOP:
168 display.div.style.top =
169 primaryDiv.offsetTop - display.div.offsetHeight + 'px';
170 display.div.style.left = newPosition.x + 'px';
171 break;
172 case SecondaryDisplayLayout.BOTTOM:
173 display.div.style.top =
174 primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px';
175 display.div.style.left = newPosition.x + 'px';
176 break;
177 }
178
179 return false;
180 },
181
182 /**
183 * Mouse down handler for dragging display rectangle.
184 * @private
185 * @param {Event} e The mouse down event.
186 */
187 onMouseDown_: function(e) {
188 if (this.mirroring_)
189 return true;
190
191 if (e.button != 0)
192 return true;
193
194 this.focusedIndex_ = null;
195 for (var i = 0; i < this.displays_.length; i++) {
196 var display = this.displays_[i];
197 if (this.displays_[i].div == e.target ||
198 (i == 0 && $('display-launcher') == e.target)) {
199 this.focusedIndex_ = i;
200 break;
201 }
202 }
203
204 for (var i = 0; i < this.displays_.length; i++) {
205 var display = this.displays_[i];
206 display.div.className = 'displays-display';
207 if (i != this.focusedIndex_)
208 continue;
209
210 display.div.classList.add('displays-focused');
211 // Do not drag the primary monitor.
212 if (i == 0)
213 continue;
214
215 this.dragging_ = {
216 display: display,
217 clickLocation: {x: e.offsetX, y: e.offsetY},
218 offset: {x: e.pageX - e.offsetX - display.div.offsetLeft,
219 y: e.pageY - e.offsetY - display.div.offsetTop}
220 };
221 }
222 this.updateSelectedDisplayDescription_();
223 return false;
224 },
225
226 /**
227 * Mouse up handler for dragging display rectangle.
228 * @private
229 * @param {Event} e The mouse up event.
230 */
231 onMouseUp_: function(e) {
232 if (this.dragging_) {
233 // Make sure the dragging location is connected.
234 var primaryDiv = this.displays_[0].div;
235 var draggingDiv = this.dragging_.display.div;
236 if (this.layout_ == SecondaryDisplayLayout.LEFT ||
237 this.layout_ == SecondaryDisplayLayout.RIGHT) {
238 var top = Math.max(draggingDiv.offsetTop,
239 primaryDiv.offsetTop - draggingDiv.offsetHeight +
240 MIN_OFFSET_OVERLAP);
241 top = Math.min(top,
242 primaryDiv.offsetTop + primaryDiv.offsetHeight -
243 MIN_OFFSET_OVERLAP);
244 draggingDiv.style.top = top + 'px';
245 } else {
246 var left = Math.max(draggingDiv.offsetLeft,
247 primaryDiv.offsetLeft - draggingDiv.offsetWidth +
248 MIN_OFFSET_OVERLAP);
249 left = Math.min(left,
250 primaryDiv.offsetLeft + primaryDiv.offsetWidth -
251 MIN_OFFSET_OVERLAP);
252 draggingDiv.style.left = left + 'px';
253 }
254 this.dragging_ = null;
255 }
256 this.updateSelectedDisplayDescription_();
257 return false;
258 },
259
260 /**
261 * Updates the description of the selected display section.
262 * @private
263 */
264 updateSelectedDisplayDescription_: function() {
265 if (this.focusedIndex_ == null ||
266 this.displays_[this.focusedIndex_] == null) {
267 $('selected-display-data-container').hidden = true;
268 $('display-configuration-arrow').hidden = true;
269 return;
270 }
271
272 $('selected-display-data-container').hidden = false;
273 var display = this.displays_[this.focusedIndex_];
274 var nameElement = $('selected-display-name');
275 while (nameElement.childNodes.length > 0)
276 nameElement.removeChild(nameElement.firstChild);
277 nameElement.appendChild(document.createTextNode(display.name));
278
279 var resolutionData = display.width + 'x' + display.height;
280 var resolutionElement = $('selected-display-resolution');
281 while (resolutionElement.childNodes.length > 0)
282 resolutionElement.removeChild(resolutionElement.firstChild);
283 resolutionElement.appendChild(document.createTextNode(resolutionData));
284
285 var arrow = $('display-configuration-arrow');
286 arrow.hidden = false;
287 arrow.style.top =
288 $('display-configurations').offsetTop - arrow.offsetHeight / 2 + 'px';
289 arrow.style.left = display.div.offsetLeft + display.div.offsetWidth / 2 -
290 arrow.offsetWidth / 2 + 'px';
291 },
292
293 /**
294 * Clears the drawing area for display rectangles.
295 * @private
296 */
297 resetDisplaysView_: function() {
298 var displaysViewHost = $('display-options-displays-view-host');
299 displaysViewHost.removeChild(displaysViewHost.firstChild);
300 this.displaysView_ = document.createElement('div');
301 this.displaysView_.id = 'display-options-displays-view';
302 this.displaysView_.onmousemove = this.onMouseMove_.bind(this);
303 this.displaysView_.onmousedown = this.onMouseDown_.bind(this);
304 this.displaysView_.onmouseup = this.onMouseUp_.bind(this);
305 displaysViewHost.appendChild(this.displaysView_);
306 },
307
308 /**
309 * Lays out the display rectangles for mirroring.
310 * @private
311 */
312 layoutMirroringDisplays_: function() {
313 // Offset pixels for secondary display rectangles.
314 /** @const */ var MIRRORING_OFFSET_PIXELS = 2;
315 // Always show two displays because there must be two displays when
316 // the display_options is enabled. Don't rely on displays_.length because
317 // there is only one display from chrome's perspective in mirror mode.
318 /** @const */ var MIN_NUM_DISPLAYS = 2;
319 /** @const */ var MIRRORING_VERTICAL_MARGIN = 20;
320
321 // The width/height should be same as the primary display:
322 var width = this.displays_[0].width * VISUAL_SCALE;
323 var height = this.displays_[0].height * VISUAL_SCALE;
324
325 var numDisplays = Math.max(MIN_NUM_DISPLAYS, this.displays_.length);
326
327 var totalWidth = width + numDisplays * MIRRORING_OFFSET_PIXELS;
328 var totalHeight = height + numDisplays * MIRRORING_OFFSET_PIXELS;
329
330 this.displaysView_.style.height = totalHeight + 'px';
331 this.displaysView_.classList.add(
332 'display-options-displays-view-mirroring');
333
334 // The displays should be centered.
335 var offsetX =
336 $('display-options-displays-view').offsetWidth / 2 - totalWidth / 2;
337
338 for (var i = 0; i < numDisplays; i++) {
339 var div = document.createElement('div');
340 div.className = 'displays-display';
341 div.style.top = i * MIRRORING_OFFSET_PIXELS + 'px';
342 div.style.left = i * MIRRORING_OFFSET_PIXELS + offsetX + 'px';
343 div.style.width = width + 'px';
344 div.style.height = height + 'px';
345 div.style.zIndex = i;
346 // set 'display-mirrored' class for the background display rectangles.
347 if (i != numDisplays - 1)
348 div.classList.add('display-mirrored');
349 this.displaysView_.appendChild(div);
350 }
351 },
352
353 /**
354 * Layouts the display rectangles according to the current layout_.
355 * @private
356 */
357 layoutDisplays_: function() {
358 var totalHeight = 0;
359 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0};
360 for (var i = 0; i < this.displays_.length; i++) {
361 var display = this.displays_[i];
362 totalHeight += display.height * VISUAL_SCALE;
363 boundingBox.left = Math.min(boundingBox.left, display.x * VISUAL_SCALE);
364 boundingBox.right = Math.max(
365 boundingBox.right, (display.x + display.width) * VISUAL_SCALE);
366 boundingBox.top = Math.min(boundingBox.top, display.y * VISUAL_SCALE);
367 boundingBox.bottom = Math.max(
368 boundingBox.bottom, (display.y + display.height) * VISUAL_SCALE);
369 }
370
371 // Prepare enough area for thisplays_view by adding the maximum height.
372 this.displaysView_.style.height = totalHeight + 'px';
373
374 // Centering the bounding box of the display rectangles.
375 var offset = {x: $('display-options-displays-view').offsetWidth / 2 -
376 (boundingBox.left + boundingBox.right) / 2,
377 y: totalHeight / 2 -
378 (boundingBox.top + boundingBox.bottom) / 2};
379
380
381 for (var i = 0; i < this.displays_.length; i++) {
382 var display = this.displays_[i];
383 var div = document.createElement('div');
384 display.div = div;
385
386 div.className = 'displays-display';
387 if (i == this.focusedIndex_)
388 div.classList.add('displays-focused');
389 div.style.width = display.width * VISUAL_SCALE + 'px';
390 div.style.height = display.height * VISUAL_SCALE + 'px';
391 div.style.lineHeight = div.style.height;
392 if (i == 0) {
393 // Assumes that first display is primary and put a grey rectangle to
394 // denote launcher below.
395 var launcher = document.createElement('div');
396 launcher.id = 'display-launcher';
397 launcher.style.width = display.div.style.width;
398 div.appendChild(launcher);
399 }
400 div.style.left = display.x * VISUAL_SCALE + offset.x + 'px';
401 div.style.top = display.y * VISUAL_SCALE + offset.y + 'px';
402
403 div.appendChild(document.createTextNode(display.name));
404
405 this.displaysView_.appendChild(div);
406 }
407 },
408
409 /**
410 * Called when the display arrangement has changed.
411 * @private
412 * @param {boolean} mirroring Whether current mode is mirroring or not.
413 * @param {Array} displays The list of the display information.
414 * @param {SecondaryDisplayLayout} layout The layout strategy.
415 * @param {number} offset The offset of the secondary display.
416 */
417 onDisplayChanged_: function(mirroring, displays, layout, offset) {
418 this.mirroring_ = mirroring;
419 this.layout_ = layout;
420 this.offset_ = offset;
421
422 $('display-options-toggle-mirroring').textContent =
423 loadTimeData.getString(
424 this.mirroring_ ? 'stopMirroring' : 'startMirroring');
425
426 // Focus to the first display next to the primary one when |displays| list
427 // is updated.
428 if (this.mirroring_)
429 this.focusedIndex_ = null;
430 else if (this.displays_.length != displays.length)
431 this.focusedIndex_ = 1;
432
433 this.displays_ = displays;
434
435 this.resetDisplaysView_();
436 if (this.mirroring_)
437 this.layoutMirroringDisplays_();
438 else
439 this.layoutDisplays_();
440 this.updateSelectedDisplayDescription_();
441 },
442 };
443
444 DisplayOptions.setDisplayInfo = function(
445 mirroring, displays, layout, offset) {
446 DisplayOptions.getInstance().onDisplayChanged_(
447 mirroring, displays, layout, offset);
448 };
449
450 // Export
451 return {
452 DisplayOptions: DisplayOptions
453 };
454 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698