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