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