| 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..e1705a4de8f0a2e24d1dd12d0097d2c1bd76e605
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/options2/chromeos/display_options.js
|
| @@ -0,0 +1,352 @@
|
| +// 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.
|
| + /** @const */ var VISUAL_SCALE = 1 / 10;
|
| +
|
| + /**
|
| + * 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() {
|
| + OptionsPage.prototype.initializePage.call(this);
|
| +
|
| + $('display-options-confirm').onclick = function() {
|
| + OptionsPage.closeOverlay();
|
| + };
|
| +
|
| + $('display-options-toggle-mirroring').onclick = (function() {
|
| + this.mirroring_ = !this.mirroring_;
|
| + chrome.send('setMirroring', [this.mirroring_]);
|
| + }).bind(this);
|
| +
|
| + chrome.send('getDisplayInfo');
|
| + },
|
| +
|
| + /**
|
| + * Mouse move handler for dragging display rectangle.
|
| + * @private
|
| + * @param {Event} e The mouse move event.
|
| + */
|
| + onMouseMove_: function(e) {
|
| + if (!this.dragging_)
|
| + 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)
|
| + 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
|
| + };
|
| + var new_position = {
|
| + x: mouse_position.x - this.dragging_.click_location.x,
|
| + y: mouse_position.y - this.dragging_.click_location.y
|
| + };
|
| +
|
| + 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:
|
| + display.div.style.left =
|
| + primary_div.offsetLeft + primary_div.offsetWidth + 'px';
|
| + display.div.style.top = new_position.y + 'px';
|
| + break;
|
| + case SecondaryDisplayLayout.LEFT:
|
| + display.div.style.left =
|
| + primary_div.offsetLeft - display.div.offsetWidth + 'px';
|
| + display.div.style.top = new_position.y + 'px';
|
| + break;
|
| + case SecondaryDisplayLayout.TOP:
|
| + display.div.style.top =
|
| + primary_div.offsetTop - display.div.offsetHeight + 'px';
|
| + display.div.style.left = new_position.x + 'px';
|
| + break;
|
| + case SecondaryDisplayLayout.BOTTOM:
|
| + 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_)
|
| + return true;
|
| +
|
| + if (e.button != 0)
|
| + return true;
|
| +
|
| + if (e.target == this.displays_view_)
|
| + return true;
|
| +
|
| + for (var i = 0; i < this.displays_.length; i++) {
|
| + var display = this.displays_[i];
|
| + if (display.div == e.target) {
|
| + // Do not drag the primary monitor.
|
| + if (i == 0)
|
| + return true;
|
| +
|
| + this.focused_index_ = i;
|
| + this.dragging_ = {
|
| + 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)
|
| + display.div.className += ' displays-focused';
|
| + } else if (display.div.className.indexOf('displays-focused') >= 0) {
|
| + // We can assume that '-primary' monitor doesn't have '-focused'.
|
| + this.displays_[i].div.className = 'displays-display';
|
| + }
|
| + }
|
| + 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;
|
| + },
|
| +
|
| + /**
|
| + * Clears the drawing area for display rectangles.
|
| + * @private
|
| + */
|
| + 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_);
|
| + },
|
| +
|
| + /**
|
| + * Lays out the display rectangles for mirroring.
|
| + * @private
|
| + */
|
| + layoutMirroringDisplays_: function() {
|
| + // The width/height should be same as the primary display:
|
| + var width = this.displays_[0].width * VISUAL_SCALE;
|
| + var height = this.displays_[0].height * VISUAL_SCALE;
|
| +
|
| + 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)
|
| + 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 * VISUAL_SCALE;
|
| + total_size.height += this.displays_[i].height * VISUAL_SCALE;
|
| + }
|
| +
|
| + 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)
|
| + 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)
|
| + div.className += ' displays-primary';
|
| + else if (i == this.focused_index_)
|
| + div.className += ' displays-focused';
|
| + div.style.width = display.width * VISUAL_SCALE + 'px';
|
| + div.style.height = display.height * VISUAL_SCALE + 'px';
|
| + div.style.lineHeight = div.style.height;
|
| + switch (this.layout_) {
|
| + case SecondaryDisplayLayout.RIGHT:
|
| + display.div.style.top = '0';
|
| + display.div.style.left = base_point.x + 'px';
|
| + base_point.x += display.width * VISUAL_SCALE;
|
| + break;
|
| + case SecondaryDisplayLayout.LEFT:
|
| + display.div.style.top = '0';
|
| + base_point.x -= display.width * VISUAL_SCALE;
|
| + display.div.style.left = base_point.x + 'px';
|
| + break;
|
| + case SecondaryDisplayLayout.TOP:
|
| + display.div.style.left = '0';
|
| + base_point.y -= display.height * VISUAL_SCALE;
|
| + display.div.style.top = base_point.y + 'px';
|
| + break;
|
| + case SecondaryDisplayLayout.BOTTOM:
|
| + display.div.style.left = '0';
|
| + display.div.style.top = base_point.y + 'px';
|
| + base_point.y += display.height * VISUAL_SCALE;
|
| + 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.layout_ = layout;
|
| +
|
| + $('display-options-toggle-mirroring').textContent =
|
| + loadTimeData.getString(
|
| + this.mirroring_ ? 'stopMirroring' : 'startMirroring');
|
| +
|
| + // Focus to the first display next to the primary one when |displays| list
|
| + // is updated.
|
| + if (this.displays_.length != displays.length)
|
| + this.focused_index_ = 1;
|
| +
|
| + this.displays_ = displays;
|
| +
|
| + if (this.displays_.length <= 1)
|
| + return;
|
| +
|
| + this.resetDisplaysView_();
|
| + if (this.mirroring_)
|
| + this.layoutMirroringDisplays_();
|
| + else
|
| + this.layoutDisplays_();
|
| + },
|
| + };
|
| +
|
| + DisplayOptions.setDisplayInfo = function(mirroring, displays, layout) {
|
| + DisplayOptions.getInstance().onDisplayChanged_(mirroring, displays, layout);
|
| + };
|
| +
|
| + // Export
|
| + return {
|
| + DisplayOptions: DisplayOptions
|
| + };
|
| +});
|
|
|