Home | History | Annotate | Download | only in net_internals
      1 // Copyright (c) 2010 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 /**
      6  * This view implements a vertically split display with a draggable divider.
      7  *
      8  *                  <<-- sizer -->>
      9  *
     10  *  +----------------------++----------------+
     11  *  |                      ||                |
     12  *  |                      ||                |
     13  *  |                      ||                |
     14  *  |                      ||                |
     15  *  |       leftView       ||   rightView    |
     16  *  |                      ||                |
     17  *  |                      ||                |
     18  *  |                      ||                |
     19  *  |                      ||                |
     20  *  |                      ||                |
     21  *  +----------------------++----------------+
     22  *
     23  * @param {!View} leftView The widget to position on the left.
     24  * @param {!View} rightView The widget to position on the right.
     25  * @param {!DivView} sizerView The widget that will serve as draggable divider.
     26  * @constructor
     27  */
     28 function ResizableVerticalSplitView(leftView, rightView, sizerView) {
     29   View.call(this);
     30 
     31   this.leftView_ = leftView;
     32   this.rightView_ = rightView;
     33   this.sizerView_ = sizerView;
     34 
     35   // Setup the "sizer" so it can be dragged left/right to reposition the
     36   // vertical split.
     37   sizerView.getNode().addEventListener(
     38       'mousedown', this.onDragSizerStart_.bind(this), true);
     39 }
     40 
     41 inherits(ResizableVerticalSplitView, View);
     42 
     43 // Minimum width to size panels to, in pixels.
     44 ResizableVerticalSplitView.MIN_PANEL_WIDTH = 50;
     45 
     46 /**
     47  * Repositions all of the elements to fit the window.
     48  */
     49 ResizableVerticalSplitView.prototype.setGeometry = function(
     50     left, top, width, height) {
     51   ResizableVerticalSplitView.superClass_.setGeometry.call(
     52       this, left, top, width, height);
     53 
     54   // If this is the first setGeometry(), initialize the split point at 50%.
     55   if (!this.leftSplit_)
     56     this.leftSplit_ = parseInt((width / 2).toFixed(0));
     57 
     58   // Calculate the horizontal split points.
     59   var leftboxWidth = this.leftSplit_;
     60   var sizerWidth = this.sizerView_.getWidth();
     61   var rightboxWidth = width - (leftboxWidth + sizerWidth);
     62 
     63   // Don't let the right pane get too small.
     64   if (rightboxWidth < ResizableVerticalSplitView.MIN_PANEL_WIDTH) {
     65     rightboxWidth = ResizableVerticalSplitView.MIN_PANEL_WIDTH;
     66     leftboxWidth = width - (sizerWidth + rightboxWidth);
     67   }
     68 
     69   // Position the boxes using calculated split points.
     70   this.leftView_.setGeometry(left, top, leftboxWidth, height);
     71   this.sizerView_.setGeometry(this.leftView_.getRight(), top,
     72                               sizerWidth, height);
     73   this.rightView_.setGeometry(this.sizerView_.getRight(), top,
     74                               rightboxWidth, height);
     75 };
     76 
     77 ResizableVerticalSplitView.prototype.show = function(isVisible) {
     78   ResizableVerticalSplitView.superClass_.show.call(this, isVisible);
     79   this.leftView_.show(isVisible);
     80   this.sizerView_.show(isVisible);
     81   this.rightView_.show(isVisible);
     82 };
     83 
     84 /**
     85  * Called once we have clicked into the sizer. Starts capturing the mouse
     86  * position to implement dragging.
     87  */
     88 ResizableVerticalSplitView.prototype.onDragSizerStart_ = function(event) {
     89   this.sizerMouseMoveListener_ = this.onDragSizer.bind(this);
     90   this.sizerMouseUpListener_ = this.onDragSizerEnd.bind(this);
     91 
     92   window.addEventListener('mousemove', this.sizerMouseMoveListener_, true);
     93   window.addEventListener('mouseup', this.sizerMouseUpListener_, true);
     94 
     95   event.preventDefault();
     96 };
     97 
     98 /**
     99  * Called when the mouse has moved after dragging started.
    100  */
    101 ResizableVerticalSplitView.prototype.onDragSizer = function(event) {
    102   // Convert from page coordinates, to view coordinates.
    103   this.leftSplit_ = (event.pageX - this.getLeft());
    104 
    105   // Avoid shrinking the left box too much.
    106   this.leftSplit_ = Math.max(
    107       this.leftSplit_, ResizableVerticalSplitView.MIN_PANEL_WIDTH);
    108   // Avoid shrinking the right box too much.
    109   this.leftSplit_ = Math.min(
    110       this.leftSplit_,
    111       this.getWidth() - ResizableVerticalSplitView.MIN_PANEL_WIDTH);
    112 
    113   // Force a layout with the new |leftSplit_|.
    114   this.setGeometry(
    115       this.getLeft(), this.getTop(), this.getWidth(), this.getHeight());
    116 };
    117 
    118 /**
    119  * Called once the mouse has been released, and the dragging is over.
    120  */
    121 ResizableVerticalSplitView.prototype.onDragSizerEnd = function(event) {
    122   window.removeEventListener('mousemove', this.sizerMouseMoveListener_, true);
    123   window.removeEventListener('mouseup', this.sizerMouseUpListener_, true);
    124 
    125   this.sizerMouseMoveListener_ = null;
    126   this.sizerMouseUpListener_ = null;
    127 
    128   event.preventDefault();
    129 };
    130