Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
     17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
     20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /**
     30  * @constructor
     31  * @extends {WebInspector.View}
     32  * @param {boolean} isVertical
     33  * @param {boolean} secondIsSidebar
     34  * @param {string=} settingName
     35  * @param {number=} defaultSidebarWidth
     36  * @param {number=} defaultSidebarHeight
     37  * @param {boolean=} constraintsInDip
     38  */
     39 WebInspector.SplitView = function(isVertical, secondIsSidebar, settingName, defaultSidebarWidth, defaultSidebarHeight, constraintsInDip)
     40 {
     41     WebInspector.View.call(this);
     42 
     43     this.element.classList.add("split-view");
     44 
     45     this._mainView = new WebInspector.VBox();
     46     this._mainElement = this._mainView.element;
     47     this._mainElement.className = "split-view-contents split-view-main vbox"; // Override
     48 
     49     this._sidebarView = new WebInspector.VBox();
     50     this._sidebarElement = this._sidebarView.element;
     51     this._sidebarElement.className = "split-view-contents split-view-sidebar vbox"; // Override
     52 
     53     this._resizerElement = this.element.createChild("div", "split-view-resizer");
     54     this._resizerElement.createChild("div", "split-view-resizer-border");
     55     if (secondIsSidebar) {
     56         this._mainView.show(this.element);
     57         this._sidebarView.show(this.element);
     58     } else {
     59         this._sidebarView.show(this.element);
     60         this._mainView.show(this.element);
     61     }
     62 
     63     this._resizerWidget = new WebInspector.ResizerWidget();
     64     this._resizerWidget.setEnabled(true);
     65     this._resizerWidget.addEventListener(WebInspector.ResizerWidget.Events.ResizeStart, this._onResizeStart, this);
     66     this._resizerWidget.addEventListener(WebInspector.ResizerWidget.Events.ResizeUpdate, this._onResizeUpdate, this);
     67     this._resizerWidget.addEventListener(WebInspector.ResizerWidget.Events.ResizeEnd, this._onResizeEnd, this);
     68 
     69     this._defaultSidebarWidth = defaultSidebarWidth || 200;
     70     this._defaultSidebarHeight = defaultSidebarHeight || this._defaultSidebarWidth;
     71     this._constraintsInDip = !!constraintsInDip;
     72     this._settingName = settingName;
     73 
     74     this.setSecondIsSidebar(secondIsSidebar);
     75 
     76     this._innerSetVertical(isVertical);
     77     this._showMode = WebInspector.SplitView.ShowMode.Both;
     78 
     79     // Should be called after isVertical has the right value.
     80     this.installResizer(this._resizerElement);
     81 }
     82 
     83 /** @typedef {{showMode: string, size: number}} */
     84 WebInspector.SplitView.SettingForOrientation;
     85 
     86 WebInspector.SplitView.ShowMode = {
     87     Both: "Both",
     88     OnlyMain: "OnlyMain",
     89     OnlySidebar: "OnlySidebar"
     90 }
     91 
     92 WebInspector.SplitView.Events = {
     93     SidebarSizeChanged: "SidebarSizeChanged",
     94     ShowModeChanged: "ShowModeChanged"
     95 }
     96 
     97 WebInspector.SplitView.MinPadding = 20;
     98 
     99 WebInspector.SplitView.prototype = {
    100     /**
    101      * @return {boolean}
    102      */
    103     isVertical: function()
    104     {
    105         return this._isVertical;
    106     },
    107 
    108     /**
    109      * @param {boolean} isVertical
    110      */
    111     setVertical: function(isVertical)
    112     {
    113         if (this._isVertical === isVertical)
    114             return;
    115 
    116         this._innerSetVertical(isVertical);
    117 
    118         if (this.isShowing())
    119             this._updateLayout();
    120     },
    121 
    122     /**
    123      * @param {boolean} isVertical
    124      */
    125     _innerSetVertical: function(isVertical)
    126     {
    127         this.element.classList.remove(this._isVertical ? "hbox" : "vbox");
    128         this._isVertical = isVertical;
    129         this.element.classList.add(this._isVertical ? "hbox" : "vbox");
    130         delete this._resizerElementSize;
    131         this._sidebarSize = -1;
    132         this._restoreSidebarSizeFromSettings();
    133         if (this._shouldSaveShowMode)
    134             this._restoreAndApplyShowModeFromSettings();
    135         this._updateShowHideSidebarButton();
    136         // FIXME: reverse SplitView.isVertical meaning.
    137         this._resizerWidget.setVertical(!isVertical);
    138         this.invalidateConstraints();
    139     },
    140 
    141     /**
    142      * @param {boolean=} animate
    143      */
    144     _updateLayout: function(animate)
    145     {
    146         delete this._totalSize; // Lazy update.
    147         delete this._totalSizeOtherDimension;
    148 
    149         // Remove properties that might affect total size calculation.
    150         this._mainElement.style.removeProperty("width");
    151         this._mainElement.style.removeProperty("height");
    152         this._sidebarElement.style.removeProperty("width");
    153         this._sidebarElement.style.removeProperty("height");
    154 
    155         this._innerSetSidebarSize(this._preferredSidebarSize(), !!animate);
    156     },
    157 
    158     /**
    159      * @return {!Element}
    160      */
    161     mainElement: function()
    162     {
    163         return this._mainElement;
    164     },
    165 
    166     /**
    167      * @return {!Element}
    168      */
    169     sidebarElement: function()
    170     {
    171         return this._sidebarElement;
    172     },
    173 
    174     /**
    175      * @return {boolean}
    176      */
    177     isSidebarSecond: function()
    178     {
    179         return this._secondIsSidebar;
    180     },
    181 
    182     enableShowModeSaving: function()
    183     {
    184         this._shouldSaveShowMode = true;
    185         this._restoreAndApplyShowModeFromSettings();
    186     },
    187 
    188     /**
    189      * @return {string}
    190      */
    191     showMode: function()
    192     {
    193         return this._showMode;
    194     },
    195 
    196     /**
    197      * @param {boolean} secondIsSidebar
    198      */
    199     setSecondIsSidebar: function(secondIsSidebar)
    200     {
    201         this._mainElement.classList.toggle("split-view-contents-first", secondIsSidebar);
    202         this._mainElement.classList.toggle("split-view-contents-second", !secondIsSidebar);
    203         this._sidebarElement.classList.toggle("split-view-contents-first", !secondIsSidebar);
    204         this._sidebarElement.classList.toggle("split-view-contents-second", secondIsSidebar);
    205 
    206         // Make sure second is last in the children array.
    207         if (secondIsSidebar) {
    208             if (this._sidebarElement.parentElement && this._sidebarElement.nextSibling)
    209                 this.element.appendChild(this._sidebarElement);
    210         } else {
    211             if (this._mainElement.parentElement && this._mainElement.nextSibling)
    212                 this.element.appendChild(this._mainElement);
    213         }
    214 
    215         this._secondIsSidebar = secondIsSidebar;
    216     },
    217 
    218     /**
    219      * @return {?string}
    220      */
    221     sidebarSide: function()
    222     {
    223         if (this._showMode !== WebInspector.SplitView.ShowMode.Both)
    224             return null;
    225         return this._isVertical ?
    226             (this._secondIsSidebar ? "right" : "left") :
    227             (this._secondIsSidebar ? "bottom" : "top");
    228     },
    229 
    230     /**
    231      * @return {number}
    232      */
    233     preferredSidebarSize: function()
    234     {
    235         return this._preferredSidebarSize();
    236     },
    237 
    238     /**
    239      * @return {!Element}
    240      */
    241     resizerElement: function()
    242     {
    243         return this._resizerElement;
    244     },
    245 
    246     /**
    247      * @param {boolean=} animate
    248      */
    249     hideMain: function(animate)
    250     {
    251         this._showOnly(this._sidebarView, this._mainView, animate);
    252         this._updateShowMode(WebInspector.SplitView.ShowMode.OnlySidebar);
    253     },
    254 
    255     /**
    256      * @param {boolean=} animate
    257      */
    258     hideSidebar: function(animate)
    259     {
    260         this._showOnly(this._mainView, this._sidebarView, animate);
    261         this._updateShowMode(WebInspector.SplitView.ShowMode.OnlyMain);
    262     },
    263 
    264     /**
    265      * @override
    266      */
    267     detachChildViews: function()
    268     {
    269         this._mainView.detachChildViews();
    270         this._sidebarView.detachChildViews();
    271     },
    272 
    273     /**
    274      * @param {!WebInspector.View} sideToShow
    275      * @param {!WebInspector.View} sideToHide
    276      * @param {boolean=} animate
    277      */
    278     _showOnly: function(sideToShow, sideToHide, animate)
    279     {
    280         this._cancelAnimation();
    281 
    282         /**
    283          * @this {WebInspector.SplitView}
    284          */
    285         function callback()
    286         {
    287             sideToShow.show(this.element);
    288             sideToHide.detach();
    289             sideToShow.element.classList.add("maximized");
    290             sideToHide.element.classList.remove("maximized");
    291             this._resizerElement.classList.add("hidden");
    292             this._removeAllLayoutProperties();
    293         }
    294 
    295         if (animate) {
    296             this._animate(true, callback.bind(this));
    297         } else {
    298             callback.call(this);
    299             this.doResize();
    300         }
    301 
    302         this._sidebarSize = -1;
    303         this.setResizable(false);
    304     },
    305 
    306     _removeAllLayoutProperties: function()
    307     {
    308         this._sidebarElement.style.removeProperty("flexBasis");
    309 
    310         this._mainElement.style.removeProperty("width");
    311         this._mainElement.style.removeProperty("height");
    312         this._sidebarElement.style.removeProperty("width");
    313         this._sidebarElement.style.removeProperty("height");
    314 
    315         this._resizerElement.style.removeProperty("left");
    316         this._resizerElement.style.removeProperty("right");
    317         this._resizerElement.style.removeProperty("top");
    318         this._resizerElement.style.removeProperty("bottom");
    319 
    320         this._resizerElement.style.removeProperty("margin-left");
    321         this._resizerElement.style.removeProperty("margin-right");
    322         this._resizerElement.style.removeProperty("margin-top");
    323         this._resizerElement.style.removeProperty("margin-bottom");
    324     },
    325 
    326     /**
    327      * @param {boolean=} animate
    328      */
    329     showBoth: function(animate)
    330     {
    331        if (this._showMode === WebInspector.SplitView.ShowMode.Both)
    332             animate = false;
    333 
    334         this._cancelAnimation();
    335         this._mainElement.classList.remove("maximized");
    336         this._sidebarElement.classList.remove("maximized");
    337         this._resizerElement.classList.remove("hidden");
    338 
    339         this._mainView.show(this.element);
    340         this._sidebarView.show(this.element);
    341         // Order views in DOM properly.
    342         this.setSecondIsSidebar(this._secondIsSidebar);
    343 
    344         this._sidebarSize = -1;
    345         this.setResizable(true);
    346         this._updateShowMode(WebInspector.SplitView.ShowMode.Both);
    347         this._updateLayout(animate);
    348     },
    349 
    350     /**
    351      * @param {boolean} resizable
    352      */
    353     setResizable: function(resizable)
    354     {
    355         this._resizerWidget.setEnabled(resizable);
    356     },
    357 
    358     /**
    359      * @return {boolean}
    360      */
    361     isResizable: function()
    362     {
    363         return this._resizerWidget.isEnabled();
    364     },
    365 
    366     /**
    367      * @param {number} size
    368      */
    369     setSidebarSize: function(size)
    370     {
    371         size *= WebInspector.zoomManager.zoomFactor();
    372         this._savedSidebarSize = size;
    373         this._saveSetting();
    374         this._innerSetSidebarSize(size, false, true);
    375     },
    376 
    377     /**
    378      * @return {number}
    379      */
    380     sidebarSize: function()
    381     {
    382         var size = Math.max(0, this._sidebarSize);
    383         return size / WebInspector.zoomManager.zoomFactor();
    384     },
    385 
    386     /**
    387      * Returns total size in DIP.
    388      * @return {number}
    389      */
    390     _totalSizeDIP: function()
    391     {
    392         if (!this._totalSize) {
    393             this._totalSize = this._isVertical ? this.element.offsetWidth : this.element.offsetHeight;
    394             this._totalSizeOtherDimension = this._isVertical ? this.element.offsetHeight : this.element.offsetWidth;
    395         }
    396         return this._totalSize * WebInspector.zoomManager.zoomFactor();
    397     },
    398 
    399     /**
    400      * @param {string} showMode
    401      */
    402     _updateShowMode: function(showMode)
    403     {
    404         this._showMode = showMode;
    405         this._saveShowModeToSettings();
    406         this._updateShowHideSidebarButton();
    407         this.dispatchEventToListeners(WebInspector.SplitView.Events.ShowModeChanged, showMode);
    408         this.invalidateConstraints();
    409     },
    410 
    411     /**
    412      * @param {number} size
    413      * @param {boolean} animate
    414      * @param {boolean=} userAction
    415      */
    416     _innerSetSidebarSize: function(size, animate, userAction)
    417     {
    418         if (this._showMode !== WebInspector.SplitView.ShowMode.Both || !this.isShowing())
    419             return;
    420 
    421         size = this._applyConstraints(size, userAction);
    422         if (this._sidebarSize === size)
    423             return;
    424 
    425         if (!this._resizerElementSize)
    426             this._resizerElementSize = this._isVertical ? this._resizerElement.offsetWidth : this._resizerElement.offsetHeight;
    427 
    428         // Invalidate layout below.
    429 
    430         this._removeAllLayoutProperties();
    431 
    432         // this._totalSize is available below since we successfully applied constraints.
    433         var sidebarSizeValue = (size / WebInspector.zoomManager.zoomFactor()) + "px";
    434         var mainSizeValue = (this._totalSize - size / WebInspector.zoomManager.zoomFactor()) + "px";
    435         this.sidebarElement().style.flexBasis = sidebarSizeValue;
    436 
    437         // Make both sides relayout boundaries.
    438         if (this._isVertical) {
    439             this._sidebarElement.style.width = sidebarSizeValue;
    440             this._mainElement.style.width = mainSizeValue;
    441             this._sidebarElement.style.height = this._totalSizeOtherDimension + "px";
    442             this._mainElement.style.height = this._totalSizeOtherDimension + "px";
    443         } else {
    444             this._sidebarElement.style.height = sidebarSizeValue;
    445             this._mainElement.style.height = mainSizeValue;
    446             this._sidebarElement.style.width = this._totalSizeOtherDimension + "px";
    447             this._mainElement.style.width = this._totalSizeOtherDimension + "px";
    448         }
    449 
    450         // Position resizer.
    451         if (this._isVertical) {
    452             if (this._secondIsSidebar) {
    453                 this._resizerElement.style.right = sidebarSizeValue;
    454                 this._resizerElement.style.marginRight = -this._resizerElementSize / 2 + "px";
    455             } else {
    456                 this._resizerElement.style.left = sidebarSizeValue;
    457                 this._resizerElement.style.marginLeft = -this._resizerElementSize / 2 + "px";
    458             }
    459         } else {
    460             if (this._secondIsSidebar) {
    461                 this._resizerElement.style.bottom = sidebarSizeValue;
    462                 this._resizerElement.style.marginBottom = -this._resizerElementSize / 2 + "px";
    463             } else {
    464                 this._resizerElement.style.top = sidebarSizeValue;
    465                 this._resizerElement.style.marginTop = -this._resizerElementSize / 2 + "px";
    466             }
    467         }
    468 
    469         this._sidebarSize = size;
    470 
    471         // Force layout.
    472 
    473         if (animate) {
    474             this._animate(false);
    475         } else {
    476             // No need to recalculate this._sidebarSize and this._totalSize again.
    477             this.doResize();
    478             this.dispatchEventToListeners(WebInspector.SplitView.Events.SidebarSizeChanged, this.sidebarSize());
    479         }
    480     },
    481 
    482     /**
    483      * @param {boolean} reverse
    484      * @param {function()=} callback
    485      */
    486     _animate: function(reverse, callback)
    487     {
    488         var animationTime = 50;
    489         this._animationCallback = callback;
    490 
    491         var animatedMarginPropertyName;
    492         if (this._isVertical)
    493             animatedMarginPropertyName = this._secondIsSidebar ? "margin-right" : "margin-left";
    494         else
    495             animatedMarginPropertyName = this._secondIsSidebar ? "margin-bottom" : "margin-top";
    496 
    497         var zoomFactor = WebInspector.zoomManager.zoomFactor();
    498         var marginFrom = reverse ? "0" : "-" + (this._sidebarSize / zoomFactor) + "px";
    499         var marginTo = reverse ? "-" + (this._sidebarSize / zoomFactor) + "px" : "0";
    500 
    501         // This order of things is important.
    502         // 1. Resize main element early and force layout.
    503         this.element.style.setProperty(animatedMarginPropertyName, marginFrom);
    504         if (!reverse) {
    505             suppressUnused(this._mainElement.offsetWidth);
    506             suppressUnused(this._sidebarElement.offsetWidth);
    507         }
    508 
    509         // 2. Issue onresize to the sidebar element, its size won't change.
    510         if (!reverse)
    511             this._sidebarView.doResize();
    512 
    513         // 3. Configure and run animation
    514         this.element.style.setProperty("transition", animatedMarginPropertyName + " " + animationTime + "ms linear");
    515 
    516         var boundAnimationFrame;
    517         var startTime;
    518         /**
    519          * @this {WebInspector.SplitView}
    520          */
    521         function animationFrame()
    522         {
    523             delete this._animationFrameHandle;
    524 
    525             if (!startTime) {
    526                 // Kick animation on first frame.
    527                 this.element.style.setProperty(animatedMarginPropertyName, marginTo);
    528                 startTime = window.performance.now();
    529             } else if (window.performance.now() < startTime + animationTime) {
    530                 // Process regular animation frame.
    531                 this._mainView.doResize();
    532             } else {
    533                 // Complete animation.
    534                 this._cancelAnimation();
    535                 this._mainView.doResize();
    536                 this.dispatchEventToListeners(WebInspector.SplitView.Events.SidebarSizeChanged, this.sidebarSize());
    537                 return;
    538             }
    539             this._animationFrameHandle = window.requestAnimationFrame(boundAnimationFrame);
    540         }
    541         boundAnimationFrame = animationFrame.bind(this);
    542         this._animationFrameHandle = window.requestAnimationFrame(boundAnimationFrame);
    543     },
    544 
    545     _cancelAnimation: function()
    546     {
    547         this.element.style.removeProperty("margin-top");
    548         this.element.style.removeProperty("margin-right");
    549         this.element.style.removeProperty("margin-bottom");
    550         this.element.style.removeProperty("margin-left");
    551         this.element.style.removeProperty("transition");
    552 
    553         if (this._animationFrameHandle) {
    554             window.cancelAnimationFrame(this._animationFrameHandle);
    555             delete this._animationFrameHandle;
    556         }
    557         if (this._animationCallback) {
    558             this._animationCallback();
    559             delete this._animationCallback;
    560         }
    561     },
    562 
    563     /**
    564      * @param {number} sidebarSize
    565      * @param {boolean=} userAction
    566      * @return {number}
    567      */
    568     _applyConstraints: function(sidebarSize, userAction)
    569     {
    570         var totalSize = this._totalSizeDIP();
    571         var zoomFactor = this._constraintsInDip ? 1 : WebInspector.zoomManager.zoomFactor();
    572 
    573         var constraints = this._sidebarView.constraints();
    574         var minSidebarSize = this.isVertical() ? constraints.minimum.width : constraints.minimum.height;
    575         if (!minSidebarSize)
    576             minSidebarSize = WebInspector.SplitView.MinPadding;
    577         minSidebarSize *= zoomFactor;
    578 
    579         var preferredSidebarSize = this.isVertical() ? constraints.preferred.width : constraints.preferred.height;
    580         if (!preferredSidebarSize)
    581             preferredSidebarSize = WebInspector.SplitView.MinPadding;
    582         preferredSidebarSize *= zoomFactor;
    583         // Allow sidebar to be less than preferred by explicit user action.
    584         if (sidebarSize < preferredSidebarSize)
    585             preferredSidebarSize = Math.max(sidebarSize, minSidebarSize);
    586 
    587         constraints = this._mainView.constraints();
    588         var minMainSize = this.isVertical() ? constraints.minimum.width : constraints.minimum.height;
    589         if (!minMainSize)
    590             minMainSize = WebInspector.SplitView.MinPadding;
    591         minMainSize *= zoomFactor;
    592 
    593         var preferredMainSize = this.isVertical() ? constraints.preferred.width : constraints.preferred.height;
    594         if (!preferredMainSize)
    595             preferredMainSize = WebInspector.SplitView.MinPadding;
    596         preferredMainSize *= zoomFactor;
    597         var savedMainSize = this.isVertical() ? this._savedVerticalMainSize : this._savedHorizontalMainSize;
    598         if (typeof savedMainSize !== "undefined")
    599             preferredMainSize = Math.min(preferredMainSize, savedMainSize * zoomFactor);
    600         if (userAction)
    601             preferredMainSize = minMainSize;
    602 
    603         // Enough space for preferred.
    604         var totalPreferred = preferredMainSize + preferredSidebarSize;
    605         if (totalPreferred <= totalSize)
    606             return Number.constrain(sidebarSize, preferredSidebarSize, totalSize - preferredMainSize);
    607 
    608         // Enough space for minimum.
    609         if (minMainSize + minSidebarSize <= totalSize) {
    610             var delta = totalPreferred - totalSize;
    611             var sidebarDelta = delta * preferredSidebarSize / totalPreferred;
    612             sidebarSize = preferredSidebarSize - sidebarDelta;
    613             return Number.constrain(sidebarSize, minSidebarSize, totalSize - minMainSize);
    614         }
    615 
    616         // Not enough space even for minimum sizes.
    617         return Math.max(0, totalSize - minMainSize);
    618     },
    619 
    620     wasShown: function()
    621     {
    622         this._forceUpdateLayout();
    623         WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._onZoomChanged, this);
    624     },
    625 
    626     willHide: function()
    627     {
    628         WebInspector.zoomManager.removeEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._onZoomChanged, this);
    629     },
    630 
    631     onResize: function()
    632     {
    633         this._updateLayout();
    634     },
    635 
    636     onLayout: function()
    637     {
    638         this._updateLayout();
    639     },
    640 
    641     /**
    642      * @return {!Constraints}
    643      */
    644     calculateConstraints: function()
    645     {
    646         if (this._showMode === WebInspector.SplitView.ShowMode.OnlyMain)
    647             return this._mainView.constraints();
    648         if (this._showMode === WebInspector.SplitView.ShowMode.OnlySidebar)
    649             return this._sidebarView.constraints();
    650 
    651         var mainConstraints = this._mainView.constraints();
    652         var sidebarConstraints = this._sidebarView.constraints();
    653         var min = WebInspector.SplitView.MinPadding;
    654         if (this._isVertical) {
    655             mainConstraints = mainConstraints.widthToMax(min);
    656             sidebarConstraints = sidebarConstraints.widthToMax(min);
    657             return mainConstraints.addWidth(sidebarConstraints).heightToMax(sidebarConstraints);
    658         } else {
    659             mainConstraints = mainConstraints.heightToMax(min);
    660             sidebarConstraints = sidebarConstraints.heightToMax(min);
    661             return mainConstraints.widthToMax(sidebarConstraints).addHeight(sidebarConstraints);
    662         }
    663     },
    664 
    665     /**
    666      * @param {!WebInspector.Event} event
    667      */
    668     _onResizeStart: function(event)
    669     {
    670         this._resizeStartSize = this._sidebarSize;
    671     },
    672 
    673     /**
    674      * @param {!WebInspector.Event} event
    675      */
    676     _onResizeUpdate: function(event)
    677     {
    678         var cssOffset = event.data.currentPosition - event.data.startPosition;
    679         var dipOffset = cssOffset * WebInspector.zoomManager.zoomFactor();
    680         var newSize = this._secondIsSidebar ? this._resizeStartSize - dipOffset : this._resizeStartSize + dipOffset;
    681         var constrainedSize = this._applyConstraints(newSize, true);
    682         this._savedSidebarSize = constrainedSize;
    683         this._saveSetting();
    684         this._innerSetSidebarSize(constrainedSize, false, true);
    685         if (this.isVertical())
    686             this._savedVerticalMainSize = this._totalSizeDIP() - this._sidebarSize;
    687         else
    688             this._savedHorizontalMainSize = this._totalSizeDIP() - this._sidebarSize;
    689     },
    690 
    691     /**
    692      * @param {!WebInspector.Event} event
    693      */
    694     _onResizeEnd: function(event)
    695     {
    696         delete this._resizeStartSize;
    697     },
    698 
    699     hideDefaultResizer: function()
    700     {
    701         this.uninstallResizer(this._resizerElement);
    702     },
    703 
    704     /**
    705      * @param {!Element} resizerElement
    706      */
    707     installResizer: function(resizerElement)
    708     {
    709         this._resizerWidget.addElement(resizerElement);
    710     },
    711 
    712     /**
    713      * @param {!Element} resizerElement
    714      */
    715     uninstallResizer: function(resizerElement)
    716     {
    717         this._resizerWidget.removeElement(resizerElement);
    718     },
    719 
    720     /**
    721      * @return {boolean}
    722      */
    723     hasCustomResizer: function()
    724     {
    725         var elements = this._resizerWidget.elements();
    726         return elements.length > 1 || (elements.length == 1 && elements[0] !== this._resizerElement);
    727     },
    728 
    729     /**
    730      * @param {!Element} resizer
    731      * @param {boolean} on
    732      */
    733     toggleResizer: function(resizer, on)
    734     {
    735         if (on)
    736             this.installResizer(resizer);
    737         else
    738             this.uninstallResizer(resizer);
    739     },
    740 
    741     /**
    742      * @return {?WebInspector.Setting}
    743      */
    744     _setting: function()
    745     {
    746         if (!this._settingName)
    747             return null;
    748 
    749         if (!WebInspector.settings[this._settingName])
    750             WebInspector.settings[this._settingName] = WebInspector.settings.createSetting(this._settingName, {});
    751 
    752         return WebInspector.settings[this._settingName];
    753     },
    754 
    755     /**
    756      * @return {?WebInspector.SplitView.SettingForOrientation}
    757      */
    758     _settingForOrientation: function()
    759     {
    760         var state = this._setting() ? this._setting().get() : {};
    761         return this._isVertical ? state.vertical : state.horizontal;
    762     },
    763 
    764     /**
    765      * @return {number}
    766      */
    767     _preferredSidebarSize: function()
    768     {
    769         var size = this._savedSidebarSize;
    770         if (!size) {
    771             size = this._isVertical ? this._defaultSidebarWidth : this._defaultSidebarHeight;
    772             // If we have default value in percents, calculate it on first use.
    773             if (0 < size && size < 1)
    774                 size *= this._totalSizeDIP();
    775         }
    776         return size;
    777     },
    778 
    779     _restoreSidebarSizeFromSettings: function()
    780     {
    781         var settingForOrientation = this._settingForOrientation();
    782         this._savedSidebarSize = settingForOrientation ? settingForOrientation.size : 0;
    783     },
    784 
    785     _restoreAndApplyShowModeFromSettings: function()
    786     {
    787         var orientationState = this._settingForOrientation();
    788         this._savedShowMode = orientationState ? orientationState.showMode : WebInspector.SplitView.ShowMode.Both;
    789         this._showMode = this._savedShowMode;
    790 
    791         switch (this._savedShowMode) {
    792         case WebInspector.SplitView.ShowMode.Both:
    793             this.showBoth();
    794             break;
    795         case WebInspector.SplitView.ShowMode.OnlyMain:
    796             this.hideSidebar();
    797             break;
    798         case WebInspector.SplitView.ShowMode.OnlySidebar:
    799             this.hideMain();
    800             break;
    801         }
    802     },
    803 
    804     _saveShowModeToSettings: function()
    805     {
    806         this._savedShowMode = this._showMode;
    807         this._saveSetting();
    808     },
    809 
    810     _saveSetting: function()
    811     {
    812         var setting = this._setting();
    813         if (!setting)
    814             return;
    815         var state = setting.get();
    816         var orientationState = (this._isVertical ? state.vertical : state.horizontal) || {};
    817 
    818         orientationState.size = this._savedSidebarSize;
    819         if (this._shouldSaveShowMode)
    820             orientationState.showMode = this._savedShowMode;
    821 
    822         if (this._isVertical)
    823             state.vertical = orientationState;
    824         else
    825             state.horizontal = orientationState;
    826         setting.set(state);
    827     },
    828 
    829     _forceUpdateLayout: function()
    830     {
    831         // Force layout even if sidebar size does not change.
    832         this._sidebarSize = -1;
    833         this._updateLayout();
    834     },
    835 
    836     /**
    837      * @param {!WebInspector.Event} event
    838      */
    839     _onZoomChanged: function(event)
    840     {
    841         this._forceUpdateLayout();
    842     },
    843 
    844     /**
    845      * @param {string} title
    846      * @param {string} className
    847      * @return {!WebInspector.StatusBarButton}
    848      */
    849     createShowHideSidebarButton: function(title, className)
    850     {
    851         console.assert(this.isVertical(), "Buttons for split view with horizontal split are not supported yet.");
    852 
    853         this._showHideSidebarButtonTitle = WebInspector.UIString(title);
    854         this._showHideSidebarButton = new WebInspector.StatusBarButton("", "sidebar-show-hide-button " + className, 3);
    855         this._showHideSidebarButton.addEventListener("click", buttonClicked.bind(this));
    856         this._updateShowHideSidebarButton();
    857 
    858         /**
    859          * @this {WebInspector.SplitView}
    860          * @param {!WebInspector.Event} event
    861          */
    862         function buttonClicked(event)
    863         {
    864             if (this._showMode !== WebInspector.SplitView.ShowMode.Both)
    865                 this.showBoth(true);
    866             else
    867                 this.hideSidebar(true);
    868         }
    869 
    870         return this._showHideSidebarButton;
    871     },
    872 
    873     _updateShowHideSidebarButton: function()
    874     {
    875         if (!this._showHideSidebarButton)
    876             return;
    877         var sidebarHidden = this._showMode === WebInspector.SplitView.ShowMode.OnlyMain;
    878         this._showHideSidebarButton.state = sidebarHidden ? "show" : "hide";
    879         this._showHideSidebarButton.element.classList.toggle("top-sidebar-show-hide-button", !this.isVertical() && !this.isSidebarSecond());
    880         this._showHideSidebarButton.element.classList.toggle("right-sidebar-show-hide-button", this.isVertical() && this.isSidebarSecond());
    881         this._showHideSidebarButton.element.classList.toggle("bottom-sidebar-show-hide-button", !this.isVertical() && this.isSidebarSecond());
    882         this._showHideSidebarButton.element.classList.toggle("left-sidebar-show-hide-button", this.isVertical() && !this.isSidebarSecond());
    883         this._showHideSidebarButton.title = sidebarHidden ? WebInspector.UIString("Show %s", this._showHideSidebarButtonTitle) : WebInspector.UIString("Hide %s", this._showHideSidebarButtonTitle);
    884     },
    885 
    886     __proto__: WebInspector.View.prototype
    887 }
    888