| 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 | 
| +  }; | 
| +}); | 
|  |