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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/options2/chromeos/display_options.js
diff --git a/chrome/browser/resources/options2/chromeos/display_options.js b/chrome/browser/resources/options2/chromeos/display_options.js
new file mode 100644
index 0000000000000000000000000000000000000000..737ba1ac9639383bd5307712b3583b32bd9f56aa
--- /dev/null
+++ b/chrome/browser/resources/options2/chromeos/display_options.js
@@ -0,0 +1,363 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('options', function() {
+
+ var OptionsPage = options.OptionsPage;
+
+ // The scale ratio of the display rectangle to its original size.
+ 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.
+
+ /**
+ * Enumeration of secondary display layout. THe value has to be same as the
+ * values in ash/monitor/monitor_controller.cc.
+ * @enum {number}
+ */
+ var SecondaryDisplayLayout = {
+ TOP: 0,
+ RIGHT: 1,
+ BOTTOM: 2,
+ LEFT: 3
+ };
+
+ /**
+ * Encapsulated handling of the 'Display' page.
+ * @constructor
+ */
+ function DisplayOptions() {
+ OptionsPage.call(this,
+ 'display',
+ loadTimeData.getString('displayOptionsPageTabTitle'),
+ 'display-options');
+ this.mirroring_ = false;
+ this.focused_index_ = null;
+ this.displays_ = [];
+ }
+
+ cr.addSingletonGetter(DisplayOptions);
+
+ DisplayOptions.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initialize the page.
+ */
+ initializePage: function() {
+ var self = this;
+
+ OptionsPage.prototype.initializePage.call(this);
+
+ $('display-options-confirm').onclick = function() {
+ OptionsPage.closeOverlay();
+ };
+
+ $('display-options-toggle-mirroring').onclick = function() {
+ self.mirroring_ = !self.mirroring_;
+ chrome.send('setMirroring', [self.mirroring_]);
+ };
+
+ chrome.send('getDisplayInfo');
+ },
+
+ /**
+ * Mouse move handler for dragging display rectangle.
+ * @private
+ * @param {Event} e The mouse move event.
+ */
+ onMouseMove_: function(e) {
+ 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.
+ return true;
+ }
+
+ var index = -1;
+ for (var i = 0; i < this.displays_.length; i++) {
+ if (this.displays_[i] == this.dragging.display) {
+ index = i;
+ break;
+ }
+ }
+ if (index < 0) {
yoshiki 2012/06/15 10:21:28 Remove braces.
Jun Mukai 2012/06/18 01:15:10 Done.
+ return true;
+ }
+
+ // Note that current code of moving display-rectangles doesn't work
+ // if there are >=3 displays. This is our assumption for M21.
+ // TODO(mukai): Fix the code to allow >=3 displays.
+ var mouse_position = {x: e.pageX - this.dragging.offset.x,
+ 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.
+ var new_position = {
+ x: mouse_position.x - this.dragging.click_location.x,
+ 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.
+
+ var primary_div = this.displays_[0].div;
+ var display = this.dragging.display;
+
+ // Separate the area into four (LEFT/RIGHT/TOP/BOTTOM) by the diagonals of
+ // the primary display, and decide which area the display should reside.
+ var diagonal_slope = primary_div.offsetHeight / primary_div.offsetWidth;
+ var top_down_intercept =
+ primary_div.offsetTop - primary_div.offsetLeft * diagonal_slope;
+ var bottom_up_intercept = primary_div.offsetTop +
+ primary_div.offsetHeight + primary_div.offsetLeft * diagonal_slope;
+
+ if (mouse_position.y >
+ top_down_intercept + mouse_position.x * diagonal_slope) {
+ if (mouse_position.y >
+ bottom_up_intercept - mouse_position.x * diagonal_slope) {
+ this.layout_ = SecondaryDisplayLayout.BOTTOM;
+ } else {
+ this.layout_ = SecondaryDisplayLayout.LEFT;
+ }
+ } else {
+ if (mouse_position.y >
+ bottom_up_intercept - mouse_position.x * diagonal_slope) {
+ this.layout_ = SecondaryDisplayLayout.RIGHT;
+ } else {
+ this.layout_ = SecondaryDisplayLayout.TOP;
+ }
+ }
+
+ if (this.layout_ == SecondaryDisplayLayout.LEFT ||
+ this.layout_ == SecondaryDisplayLayout.RIGHT) {
+ if (new_position.y > primary_div.offsetTop + primary_div.offsetHeight) {
+ this.layout_ = SecondaryDisplayLayout.BOTTOM;
+ } else if (new_position.y + display.div.offsetHeight <
+ primary_div.offsetTop) {
+ this.layout_ = SecondaryDisplayLayout.TOP;
+ }
+ } else {
+ if (new_position.y > primary_div.offsetLeft + primary_div.offsetWidth) {
+ this.layout_ = SecondaryDisplayLayout.RIGHT;
+ } else if (new_position.y + display.div.offsetWidth <
+ primary_div.offstLeft) {
+ this.layout_ = SecondaryDisplayLayout.LEFT;
+ }
+ }
+
+ switch (this.layout_) {
+ 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.
+ display.div.style.left =
+ primary_div.offsetLeft + primary_div.offsetWidth + 'px';
+ display.div.style.top = new_position.y + 'px';
+ break;
+ case SecondaryDisplayLayout.LEFT:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ display.div.style.left =
+ primary_div.offsetLeft - display.div.offsetWidth + 'px';
+ display.div.style.top = new_position.y + 'px';
+ break;
+ case SecondaryDisplayLayout.TOP:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ display.div.style.top =
+ primary_div.offsetTop - display.div.offsetHeight + 'px';
+ display.div.style.left = new_position.x + 'px';
+ break;
+ case SecondaryDisplayLayout.BOTTOM:
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ display.div.style.top =
+ primary_div.offsetTop + primary_div.offsetHeight + 'px';
+ display.div.style.left = new_position.x + 'px';
+ break;
+ }
+
+ return false;
+ },
+
+ /**
+ * Mouse down handler for dragging display rectangle.
+ * @private
+ * @param {Event} e The mouse down event.
+ */
+ onMouseDown_: function(e) {
+ if (this.mirroring_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ return true;
+ }
+
+ if (e.button != 0) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ return true;
+ }
+
+ if (e.target == this.displays_view_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ return true;
+ }
+
+ for (var i = 0; i < this.displays_.length; i++) {
+ var display = this.displays_[i];
+ if (display.div == e.target) {
+ if (i == 0) {
+ // Do not drag the primary monitor.
+ return true;
+ }
+
+ this.focused_index_ = i;
+ 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.
+ display: display,
+ click_location: {x: e.offsetX, y: e.offsetY},
+ offset: {x: e.pageX - e.offsetX - display.div.offsetLeft,
+ y: e.pageY - e.offsetY - display.div.offsetTop}
+ };
+ 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.
+ display.div.className += ' displays-focused';
+ }
+ } else if (display.div.className.indexOf('displays-focused') >= 0) {
+ 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
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Mouse up handler for dragging display rectangle.
+ * @private
+ * @param {Event} e The mouse up event.
+ */
+ onMouseUp_: function(e) {
+ if (this.dragging) {
+ this.dragging = null;
+ chrome.send('setDisplayLayout', [this.layout_]);
+ }
+ return false;
+ },
+
+ resetDisplaysView_: function() {
+ var displays_view_host = $('display-options-displays-view-host');
+ displays_view_host.removeChild(displays_view_host.firstChild);
+ this.displays_view_ = document.createElement('div');
+ this.displays_view_.id = 'display-options-displays-view';
+ this.displays_view_.onmousemove = this.onMouseMove_.bind(this);
+ this.displays_view_.onmousedown = this.onMouseDown_.bind(this);
+ this.displays_view_.onmouseup = this.onMouseUp_.bind(this);
+ displays_view_host.appendChild(this.displays_view_);
+ },
+
+ /**
+ * Layouts the display rectangles for mirroring.
+ * @private
+ */
+ layoutMirroringDisplays_: function() {
+ // The width/height should be same as the primary display:
+ var width = this.displays_[0].width * kVisualScale;
+ var height = this.displays_[0].height * kVisualScale;
+
+ this.displays_view_.style.height =
+ height + this.displays_.length * 2 + 'px';
+
+ for (var i = 0; i < this.displays_.length; i++) {
+ var div = document.createElement('div');
+ this.displays_[i].div = div;
+ div.className = 'displays-display';
+ div.style.top = i * 2 + 'px';
+ div.style.left = i * 2 + 'px';
+ div.style.width = width + 'px';
+ div.style.height = height + 'px';
+ div.style.zIndex = i;
+ if (i == this.displays_.length - 1) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ div.className += ' displays-primary';
+ }
+ this.displays_view_.appendChild(div);
+ }
+ },
+
+ /**
+ * Layouts the display rectangles according to the current layout_.
+ * @private
+ */
+ layoutDisplays_: function() {
+ var total_size = {width: 0, height: 0};
+ for (var i = 0; i < this.displays_.length; i++) {
+ total_size.width += this.displays_[i].width * kVisualScale;
+ total_size.height += this.displays_[i].height * kVisualScale;
+ }
+
+ this.displays_view_.style.width = total_size.width + 'px';
+ this.displays_view_.style.height = total_size.height + 'px';
+
+ var base_point = {x: 0, y: 0};
+ if (this.layout_ == SecondaryDisplayLayout.LEFT) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ base_point.x = total_size.width;
+ } else if (this.layout_ == SecondaryDisplayLayout.TOP) {
+ base_point.y = total_size.height;
+ }
+
+ for (var i = 0; i < this.displays_.length; i++) {
+ var display = this.displays_[i];
+ var div = document.createElement('div');
+ display.div = div;
+
+ div.className = 'displays-display';
+ if (i == 0) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ div.className += ' displays-primary';
+ } else if (i == this.focused_index_) {
+ div.className += ' displays-focused';
+ }
+ div.style.width = display.width * kVisualScale + 'px';
+ div.style.height = display.height * kVisualScale + 'px';
+ div.style.lineHeight = div.style.height;
+ switch (this.layout_) {
+ case SecondaryDisplayLayout.RIGHT:
+ 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.
+ display.div.style.left = base_point.x + 'px';
+ base_point.x += display.width * kVisualScale;
+ break;
+ case SecondaryDisplayLayout.LEFT:
+ display.div.style.top = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ base_point.x -= display.width * kVisualScale;
+ display.div.style.left = base_point.x + 'px';
+ break;
+ case SecondaryDisplayLayout.TOP:
+ display.div.style.left = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ base_point.y -= display.height * kVisualScale;
+ display.div.style.top = base_point.y + 'px';
+ break;
+ case SecondaryDisplayLayout.BOTTOM:
+ display.div.style.left = '0px';
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ display.div.style.top = base_point.y + 'px';
+ base_point.y += display.height * kVisualScale;
+ break;
+ }
+
+ this.displays_view_.appendChild(div);
+ }
+ },
+
+ /**
+ * Called when the display arrangement has changed.
+ * @private
+ * @param {boolean} mirroring Whether current mode is mirroring or not.
+ * @param {Array} displays The list of the display information.
+ * @param {SecondaryDisplayLayout} layout The layout strategy.
+ */
+ onDisplayChanged_: function(mirroring, displays, layout) {
+ this.mirroring_ = mirroring;
+ this.displays_ = displays;
+ this.layout_ = layout;
+
+ $('display-options-toggle-mirroring').textContent =
+ loadTimeData.getString(
+ this.mirroring_ ? 'stop-mirroring' : 'start-mirroring');
+
+ if (this.displays_.length <= 1) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ return;
+ }
+
+ 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.
+ // Focus to the first display next to the primary one.
+ this.focused_index_ = 1;
+ }
+
+ this.resetDisplaysView_();
+ if (this.mirroring_) {
yoshiki 2012/06/15 10:21:28 ditto
Jun Mukai 2012/06/18 01:15:10 Done.
+ this.layoutMirroringDisplays_();
+ } else {
+ this.layoutDisplays_();
+ }
+ },
+ };
+
+ DisplayOptions.setDisplayInfo = function(mirroring, displays, layout) {
+ DisplayOptions.getInstance().onDisplayChanged_(mirroring, displays, layout);
+ };
+
+ // Export
+ return {
+ DisplayOptions: DisplayOptions
+ };
+});

Powered by Google App Engine
This is Rietveld 408576698