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