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

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

Issue 10544171: Add OptionsUI and its handler for multiple displays. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 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
7 var OptionsPage = options.OptionsPage;
8
9 // The scale ratio of the display rectangle to its original size.
10 var kVisualScale = 1 / 10;
yoshiki 2012/06/15 10:21:28 Use VISUAL_SCALE as name of constants and add @con
Jun Mukai 2012/06/18 01:15:10 Done.
11
12 /**
13 * Enumeration of secondary display layout. THe value has to be same as the
14 * values in ash/monitor/monitor_controller.cc.
15 * @enum {number}
16 */
17 var SecondaryDisplayLayout = {
18 TOP: 0,
19 RIGHT: 1,
20 BOTTOM: 2,
21 LEFT: 3
22 };
23
24 /**
25 * Encapsulated handling of the 'Display' page.
26 * @constructor
27 */
28 function DisplayOptions() {
29 OptionsPage.call(this,
30 'display',
31 loadTimeData.getString('displayOptionsPageTabTitle'),
32 'display-options');
33 this.mirroring_ = false;
34 this.focused_index_ = null;
35 this.displays_ = [];
36 }
37
38 cr.addSingletonGetter(DisplayOptions);
39
40 DisplayOptions.prototype = {
41 __proto__: OptionsPage.prototype,
42
43 /**
44 * Initialize the page.
45 */
46 initializePage: function() {
47 var self = this;
48
49 OptionsPage.prototype.initializePage.call(this);
50
51 $('display-options-confirm').onclick = function() {
52 OptionsPage.closeOverlay();
53 };
54
55 $('display-options-toggle-mirroring').onclick = function() {
56 self.mirroring_ = !self.mirroring_;
57 chrome.send('setMirroring', [self.mirroring_]);
58 };
59
60 chrome.send('getDisplayInfo');
61 },
62
63 /**
64 * Mouse move handler for dragging display rectangle.
65 * @private
66 * @param {Event} e The mouse move event.
67 */
68 onMouseMove_: function(e) {
69 if (!this.dragging) {
yoshiki 2012/06/15 10:21:28 Remove braces when the statement is only one line
Jun Mukai 2012/06/18 01:15:10 Done.
70 return true;
71 }
72
73 var index = -1;
74 for (var i = 0; i < this.displays_.length; i++) {
75 if (this.displays_[i] == this.dragging.display) {
76 index = i;
77 break;
78 }
79 }
80 if (index < 0) {
yoshiki 2012/06/15 10:21:28 Remove braces.
Jun Mukai 2012/06/18 01:15:10 Done.
81 return true;
82 }
83
84 // Note that current code of moving display-rectangles doesn't work
85 // if there are >=3 displays. This is our assumption for M21.
86 // TODO(mukai): Fix the code to allow >=3 displays.
87 var mouse_position = {x: e.pageX - this.dragging.offset.x,
88 y: e.pageY - this.dragging.offset.y};
yoshiki 2012/06/15 10:21:28 Add CRLF before the end brace because multi-line i
Jun Mukai 2012/06/18 01:15:10 Done.
89 var new_position = {
90 x: mouse_position.x - this.dragging.click_location.x,
91 y: mouse_position.y - this.dragging.click_location.y};
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
92
93 var primary_div = this.displays_[0].div;
94 var display = this.dragging.display;
95
96 // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of
97 // the primary display, and decide which area the display should reside.
98 var diagonal_slope = primary_div.offsetHeight / primary_div.offsetWidth;
99 var top_down_intercept =
100 primary_div.offsetTop - primary_div.offsetLeft * diagonal_slope;
101 var bottom_up_intercept = primary_div.offsetTop +
102 primary_div.offsetHeight + primary_div.offsetLeft * diagonal_slope;
103
104 if (mouse_position.y >
105 top_down_intercept + mouse_position.x * diagonal_slope) {
106 if (mouse_position.y >
107 bottom_up_intercept - mouse_position.x * diagonal_slope) {
108 this.layout_ = SecondaryDisplayLayout.BOTTOM;
109 } else {
110 this.layout_ = SecondaryDisplayLayout.LEFT;
111 }
112 } else {
113 if (mouse_position.y >
114 bottom_up_intercept - mouse_position.x * diagonal_slope) {
115 this.layout_ = SecondaryDisplayLayout.RIGHT;
116 } else {
117 this.layout_ = SecondaryDisplayLayout.TOP;
118 }
119 }
120
121 if (this.layout_ == SecondaryDisplayLayout.LEFT ||
122 this.layout_ == SecondaryDisplayLayout.RIGHT) {
123 if (new_position.y > primary_div.offsetTop + primary_div.offsetHeight) {
124 this.layout_ = SecondaryDisplayLayout.BOTTOM;
125 } else if (new_position.y + display.div.offsetHeight <
126 primary_div.offsetTop) {
127 this.layout_ = SecondaryDisplayLayout.TOP;
128 }
129 } else {
130 if (new_position.y > primary_div.offsetLeft + primary_div.offsetWidth) {
131 this.layout_ = SecondaryDisplayLayout.RIGHT;
132 } else if (new_position.y + display.div.offsetWidth <
133 primary_div.offstLeft) {
134 this.layout_ = SecondaryDisplayLayout.LEFT;
135 }
136 }
137
138 switch (this.layout_) {
139 case SecondaryDisplayLayout.RIGHT:
yoshiki 2012/06/15 10:21:28 Indent. "case" should be same indent as "switch".
Jun Mukai 2012/06/18 01:15:10 Done.
140 display.div.style.left =
141 primary_div.offsetLeft + primary_div.offsetWidth + 'px';
142 display.div.style.top = new_position.y + 'px';
143 break;
144 case SecondaryDisplayLayout.LEFT:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
145 display.div.style.left =
146 primary_div.offsetLeft - display.div.offsetWidth + 'px';
147 display.div.style.top = new_position.y + 'px';
148 break;
149 case SecondaryDisplayLayout.TOP:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
150 display.div.style.top =
151 primary_div.offsetTop - display.div.offsetHeight + 'px';
152 display.div.style.left = new_position.x + 'px';
153 break;
154 case SecondaryDisplayLayout.BOTTOM:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
155 display.div.style.top =
156 primary_div.offsetTop + primary_div.offsetHeight + 'px';
157 display.div.style.left = new_position.x + 'px';
158 break;
159 }
160
161 return false;
162 },
163
164 /**
165 * Mouse down handler for dragging display rectangle.
166 * @private
167 * @param {Event} e The mouse down event.
168 */
169 onMouseDown_: function(e) {
170 if (this.mirroring_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
171 return true;
172 }
173
174 if (e.button != 0) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
175 return true;
176 }
177
178 if (e.target == this.displays_view_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
179 return true;
180 }
181
182 for (var i = 0; i < this.displays_.length; i++) {
183 var display = this.displays_[i];
184 if (display.div == e.target) {
185 if (i == 0) {
186 // Do not drag the primary monitor.
187 return true;
188 }
189
190 this.focused_index_ = i;
191 this.dragging = {
yoshiki 2012/06/15 10:21:28 DisplayOptions.dragging is a private property righ
Jun Mukai 2012/06/18 01:15:10 Done.
192 display: display,
193 click_location: {x: e.offsetX, y: e.offsetY},
194 offset: {x: e.pageX - e.offsetX - display.div.offsetLeft,
195 y: e.pageY - e.offsetY - display.div.offsetTop}
196 };
197 if (display.div.className.indexOf('displays-focused') == -1) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
198 display.div.className += ' displays-focused';
199 }
200 } else if (display.div.className.indexOf('displays-focused') >= 0) {
201 this.displays_[i].div.className = 'displays-display';
yoshiki 2012/06/15 10:21:28 'displays-primary' class would be removed, right?
Jun Mukai 2012/06/18 01:15:10 displays-primary won't obtain the '-focused' class
202 }
203 }
204 return false;
205 },
206
207 /**
208 * Mouse up handler for dragging display rectangle.
209 * @private
210 * @param {Event} e The mouse up event.
211 */
212 onMouseUp_: function(e) {
213 if (this.dragging) {
214 this.dragging = null;
215 chrome.send('setDisplayLayout', [this.layout_]);
216 }
217 return false;
218 },
219
220 resetDisplaysView_: function() {
221 var displays_view_host = $('display-options-displays-view-host');
222 displays_view_host.removeChild(displays_view_host.firstChild);
223 this.displays_view_ = document.createElement('div');
224 this.displays_view_.id = 'display-options-displays-view';
225 this.displays_view_.onmousemove = this.onMouseMove_.bind(this);
226 this.displays_view_.onmousedown = this.onMouseDown_.bind(this);
227 this.displays_view_.onmouseup = this.onMouseUp_.bind(this);
228 displays_view_host.appendChild(this.displays_view_);
229 },
230
231 /**
232 * Layouts the display rectangles for mirroring.
233 * @private
234 */
235 layoutMirroringDisplays_: function() {
236 // The width/height should be same as the primary display:
237 var width = this.displays_[0].width * kVisualScale;
238 var height = this.displays_[0].height * kVisualScale;
239
240 this.displays_view_.style.height =
241 height + this.displays_.length * 2 + 'px';
242
243 for (var i = 0; i < this.displays_.length; i++) {
244 var div = document.createElement('div');
245 this.displays_[i].div = div;
246 div.className = 'displays-display';
247 div.style.top = i * 2 + 'px';
248 div.style.left = i * 2 + 'px';
249 div.style.width = width + 'px';
250 div.style.height = height + 'px';
251 div.style.zIndex = i;
252 if (i == this.displays_.length - 1) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
253 div.className += ' displays-primary';
254 }
255 this.displays_view_.appendChild(div);
256 }
257 },
258
259 /**
260 * Layouts the display rectangles according to the current layout_.
261 * @private
262 */
263 layoutDisplays_: function() {
264 var total_size = {width: 0, height: 0};
265 for (var i = 0; i < this.displays_.length; i++) {
266 total_size.width += this.displays_[i].width * kVisualScale;
267 total_size.height += this.displays_[i].height * kVisualScale;
268 }
269
270 this.displays_view_.style.width = total_size.width + 'px';
271 this.displays_view_.style.height = total_size.height + 'px';
272
273 var base_point = {x: 0, y: 0};
274 if (this.layout_ == SecondaryDisplayLayout.LEFT) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
275 base_point.x = total_size.width;
276 } else if (this.layout_ == SecondaryDisplayLayout.TOP) {
277 base_point.y = total_size.height;
278 }
279
280 for (var i = 0; i < this.displays_.length; i++) {
281 var display = this.displays_[i];
282 var div = document.createElement('div');
283 display.div = div;
284
285 div.className = 'displays-display';
286 if (i == 0) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
287 div.className += ' displays-primary';
288 } else if (i == this.focused_index_) {
289 div.className += ' displays-focused';
290 }
291 div.style.width = display.width * kVisualScale + 'px';
292 div.style.height = display.height * kVisualScale + 'px';
293 div.style.lineHeight = div.style.height;
294 switch (this.layout_) {
295 case SecondaryDisplayLayout.RIGHT:
296 display.div.style.top = '0px';
yoshiki 2012/06/15 10:21:28 Use '0' instead of '0px'.
Jun Mukai 2012/06/18 01:15:10 Done.
297 display.div.style.left = base_point.x + 'px';
298 base_point.x += display.width * kVisualScale;
299 break;
300 case SecondaryDisplayLayout.LEFT:
301 display.div.style.top = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
302 base_point.x -= display.width * kVisualScale;
303 display.div.style.left = base_point.x + 'px';
304 break;
305 case SecondaryDisplayLayout.TOP:
306 display.div.style.left = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
307 base_point.y -= display.height * kVisualScale;
308 display.div.style.top = base_point.y + 'px';
309 break;
310 case SecondaryDisplayLayout.BOTTOM:
311 display.div.style.left = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
312 display.div.style.top = base_point.y + 'px';
313 base_point.y += display.height * kVisualScale;
314 break;
315 }
316
317 this.displays_view_.appendChild(div);
318 }
319 },
320
321 /**
322 * Called when the display arrangement has changed.
323 * @private
324 * @param {boolean} mirroring Whether current mode is mirroring or not.
325 * @param {Array} displays The list of the display information.
326 * @param {SecondaryDisplayLayout} layout The layout strategy.
327 */
328 onDisplayChanged_: function(mirroring, displays, layout) {
329 this.mirroring_ = mirroring;
330 this.displays_ = displays;
331 this.layout_ = layout;
332
333 $('display-options-toggle-mirroring').textContent =
334 loadTimeData.getString(
335 this.mirroring_ ? 'stop-mirroring' : 'start-mirroring');
336
337 if (this.displays_.length <= 1) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
338 return;
339 }
340
341 if (this.focused_index_ == null) {
yoshiki 2012/06/15 10:21:28 I think focused_index_ should be reset to 1 when d
Jun Mukai 2012/06/18 01:15:10 Done.
342 // Focus to the first display next to the primary one.
343 this.focused_index_ = 1;
344 }
345
346 this.resetDisplaysView_();
347 if (this.mirroring_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
348 this.layoutMirroringDisplays_();
349 } else {
350 this.layoutDisplays_();
351 }
352 },
353 };
354
355 DisplayOptions.setDisplayInfo = function(mirroring, displays, layout) {
356 DisplayOptions.getInstance().onDisplayChanged_(mirroring, displays, layout);
357 };
358
359 // Export
360 return {
361 DisplayOptions: DisplayOptions
362 };
363 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698