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