text: /*---------------------------------------------------------------------------------------------
   *  Copyright (c) Microsoft Corporation. All rights reserved.
   *  Licensed under the MIT License. See License.txt in the project root for license information.
   *--------------------------------------------------------------------------------------------*/
  import { Emitter } from '../../../base/common/event';
  import { Disposable } from '../../../base/common/lifecycle';
  import { Scrollable } from '../../../base/common/scrollable';
  import { LinesLayout } from './linesLayout';
  import { Viewport } from '../viewModel/viewModel';
  import { ContentSizeChangedEvent } from '../viewModel/viewModelEventDispatcher';
  const SMOOTH_SCROLLING_TIME = 125;
  class EditorScrollDimensions {
      constructor(width, contentWidth, height, contentHeight) {
          width = width | 0;
          contentWidth = contentWidth | 0;
          height = height | 0;
          contentHeight = contentHeight | 0;
          if (width < 0) {
              width = 0;
          }
          if (contentWidth < 0) {
              contentWidth = 0;
          }
          if (height < 0) {
              height = 0;
          }
          if (contentHeight < 0) {
              contentHeight = 0;
          }
          this.width = width;
          this.contentWidth = contentWidth;
          this.scrollWidth = Math.max(width, contentWidth);
          this.height = height;
          this.contentHeight = contentHeight;
          this.scrollHeight = Math.max(height, contentHeight);
      }
      equals(other) {
          return (this.width === other.width
              && this.contentWidth === other.contentWidth
              && this.height === other.height
              && this.contentHeight === other.contentHeight);
      }
  }
  class EditorScrollable extends Disposable {
      constructor(smoothScrollDuration, scheduleAtNextAnimationFrame) {
          super();
          this._onDidContentSizeChange = this._register(new Emitter());
          this.onDidContentSizeChange = this._onDidContentSizeChange.event;
          this._dimensions = new EditorScrollDimensions(0, 0, 0, 0);
          this._scrollable = this._register(new Scrollable(smoothScrollDuration, scheduleAtNextAnimationFrame));
          this.onDidScroll = this._scrollable.onScroll;
      }
      getScrollable() {
          return this._scrollable;
      }
      setSmoothScrollDuration(smoothScrollDuration) {
          this._scrollable.setSmoothScrollDuration(smoothScrollDuration);
      }
      validateScrollPosition(scrollPosition) {
          return this._scrollable.validateScrollPosition(scrollPosition);
      }
      getScrollDimensions() {
          return this._dimensions;
      }
      setScrollDimensions(dimensions) {
          if (this._dimensions.equals(dimensions)) {
              return;
          }
          const oldDimensions = this._dimensions;
          this._dimensions = dimensions;
          this._scrollable.setScrollDimensions({
              width: dimensions.width,
              scrollWidth: dimensions.scrollWidth,
              height: dimensions.height,
              scrollHeight: dimensions.scrollHeight
          }, true);
          const contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);
          const contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);
          if (contentWidthChanged || contentHeightChanged) {
              this._onDidContentSizeChange.fire(new ContentSizeChangedEvent(oldDimensions.contentWidth, oldDimensions.contentHeight, dimensions.contentWidth, dimensions.contentHeight));
          }
      }
      getFutureScrollPosition() {
          return this._scrollable.getFutureScrollPosition();
      }
      getCurrentScrollPosition() {
          return this._scrollable.getCurrentScrollPosition();
      }
      setScrollPositionNow(update) {
          this._scrollable.setScrollPositionNow(update);
      }
      setScrollPositionSmooth(update) {
          this._scrollable.setScrollPositionSmooth(update);
      }
  }
  export class ViewLayout extends Disposable {
      constructor(configuration, lineCount, scheduleAtNextAnimationFrame) {
          super();
          this._configuration = configuration;
          const options = this._configuration.options;
          const layoutInfo = options.get(131 /* layoutInfo */);
          const padding = options.get(75 /* padding */);
          this._linesLayout = new LinesLayout(lineCount, options.get(59 /* lineHeight */), padding.top, padding.bottom);
          this._scrollable = this._register(new EditorScrollable(0, scheduleAtNextAnimationFrame));
          this._configureSmoothScrollDuration();
          this._scrollable.setScrollDimensions(new EditorScrollDimensions(layoutInfo.contentWidth, 0, layoutInfo.height, 0));
          this.onDidScroll = this._scrollable.onDidScroll;
          this.onDidContentSizeChange = this._scrollable.onDidContentSizeChange;
          this._updateHeight();
      }
      dispose() {
          super.dispose();
      }
      getScrollable() {
          return this._scrollable.getScrollable();
      }
      onHeightMaybeChanged() {
          this._updateHeight();
      }
      _configureSmoothScrollDuration() {
          this._scrollable.setSmoothScrollDuration(this._configuration.options.get(103 /* smoothScrolling */) ? SMOOTH_SCROLLING_TIME : 0);
      }
      // ---- begin view event handlers
      onConfigurationChanged(e) {
          const options = this._configuration.options;
          if (e.hasChanged(59 /* lineHeight */)) {
              this._linesLayout.setLineHeight(options.get(59 /* lineHeight */));
          }
          if (e.hasChanged(75 /* padding */)) {
              const padding = options.get(75 /* padding */);
              this._linesLayout.setPadding(padding.top, padding.bottom);
          }
          if (e.hasChanged(131 /* layoutInfo */)) {
              const layoutInfo = options.get(131 /* layoutInfo */);
              const width = layoutInfo.contentWidth;
              const height = layoutInfo.height;
              const scrollDimensions = this._scrollable.getScrollDimensions();
              const contentWidth = scrollDimensions.contentWidth;
              this._scrollable.setScrollDimensions(new EditorScrollDimensions(width, scrollDimensions.contentWidth, height, this._getContentHeight(width, height, contentWidth)));
          }
          else {
              this._updateHeight();
          }
          if (e.hasChanged(103 /* smoothScrolling */)) {
              this._configureSmoothScrollDuration();
          }
      }
      onFlushed(lineCount) {
          this._linesLayout.onFlushed(lineCount);
      }
      onLinesDeleted(fromLineNumber, toLineNumber) {
          this._linesLayout.onLinesDeleted(fromLineNumber, toLineNumber);
      }
      onLinesInserted(fromLineNumber, toLineNumber) {
          this._linesLayout.onLinesInserted(fromLineNumber, toLineNumber);
      }
      // ---- end view event handlers
      _getHorizontalScrollbarHeight(width, scrollWidth) {
          const options = this._configuration.options;
          const scrollbar = options.get(92 /* scrollbar */);
          if (scrollbar.horizontal === 2 /* Hidden */) {
              // horizontal scrollbar not visible
              return 0;
          }
          if (width >= scrollWidth) {
              // horizontal scrollbar not visible
              return 0;
          }
          return scrollbar.horizontalScrollbarSize;
      }
      _getContentHeight(width, height, contentWidth) {
          const options = this._configuration.options;
          let result = this._linesLayout.getLinesTotalHeight();
          if (options.get(94 /* scrollBeyondLastLine */)) {
              result += Math.max(0, height - options.get(59 /* lineHeight */) - options.get(75 /* padding */).bottom);
          }
          else {
              result += this._getHorizontalScrollbarHeight(width, contentWidth);
          }
          return result;
      }
      _updateHeight() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          const width = scrollDimensions.width;
          const height = scrollDimensions.height;
          const contentWidth = scrollDimensions.contentWidth;
          this._scrollable.setScrollDimensions(new EditorScrollDimensions(width, scrollDimensions.contentWidth, height, this._getContentHeight(width, height, contentWidth)));
      }
      // ---- Layouting logic
      getCurrentViewport() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          const currentScrollPosition = this._scrollable.getCurrentScrollPosition();
          return new Viewport(currentScrollPosition.scrollTop, currentScrollPosition.scrollLeft, scrollDimensions.width, scrollDimensions.height);
      }
      getFutureViewport() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          const currentScrollPosition = this._scrollable.getFutureScrollPosition();
          return new Viewport(currentScrollPosition.scrollTop, currentScrollPosition.scrollLeft, scrollDimensions.width, scrollDimensions.height);
      }
      _computeContentWidth(maxLineWidth) {
          const options = this._configuration.options;
          const wrappingInfo = options.get(132 /* wrappingInfo */);
          const fontInfo = options.get(44 /* fontInfo */);
          if (wrappingInfo.isViewportWrapping) {
              const layoutInfo = options.get(131 /* layoutInfo */);
              const minimap = options.get(65 /* minimap */);
              if (maxLineWidth > layoutInfo.contentWidth + fontInfo.typicalHalfwidthCharacterWidth) {
                  // This is a case where viewport wrapping is on, but the line extends above the viewport
                  if (minimap.enabled && minimap.side === 'right') {
                      // We need to accomodate the scrollbar width
                      return maxLineWidth + layoutInfo.verticalScrollbarWidth;
                  }
              }
              return maxLineWidth;
          }
          else {
              const extraHorizontalSpace = options.get(93 /* scrollBeyondLastColumn */) * fontInfo.typicalHalfwidthCharacterWidth;
              const whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth();
              return Math.max(maxLineWidth + extraHorizontalSpace, whitespaceMinWidth);
          }
      }
      setMaxLineWidth(maxLineWidth) {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          // const newScrollWidth = ;
          this._scrollable.setScrollDimensions(new EditorScrollDimensions(scrollDimensions.width, this._computeContentWidth(maxLineWidth), scrollDimensions.height, scrollDimensions.contentHeight));
          // The height might depend on the fact that there is a horizontal scrollbar or not
          this._updateHeight();
      }
      // ---- view state
      saveState() {
          const currentScrollPosition = this._scrollable.getFutureScrollPosition();
          const scrollTop = currentScrollPosition.scrollTop;
          const firstLineNumberInViewport = this._linesLayout.getLineNumberAtOrAfterVerticalOffset(scrollTop);
          const whitespaceAboveFirstLine = this._linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(firstLineNumberInViewport);
          return {
              scrollTop: scrollTop,
              scrollTopWithoutViewZones: scrollTop - whitespaceAboveFirstLine,
              scrollLeft: currentScrollPosition.scrollLeft
          };
      }
      // ---- IVerticalLayoutProvider
      changeWhitespace(callback) {
          const hadAChange = this._linesLayout.changeWhitespace(callback);
          if (hadAChange) {
              this.onHeightMaybeChanged();
          }
          return hadAChange;
      }
      getVerticalOffsetForLineNumber(lineNumber) {
          return this._linesLayout.getVerticalOffsetForLineNumber(lineNumber);
      }
      isAfterLines(verticalOffset) {
          return this._linesLayout.isAfterLines(verticalOffset);
      }
      isInTopPadding(verticalOffset) {
          return this._linesLayout.isInTopPadding(verticalOffset);
      }
      isInBottomPadding(verticalOffset) {
          return this._linesLayout.isInBottomPadding(verticalOffset);
      }
      getLineNumberAtVerticalOffset(verticalOffset) {
          return this._linesLayout.getLineNumberAtOrAfterVerticalOffset(verticalOffset);
      }
      getWhitespaceAtVerticalOffset(verticalOffset) {
          return this._linesLayout.getWhitespaceAtVerticalOffset(verticalOffset);
      }
      getLinesViewportData() {
          const visibleBox = this.getCurrentViewport();
          return this._linesLayout.getLinesViewportData(visibleBox.top, visibleBox.top + visibleBox.height);
      }
      getLinesViewportDataAtScrollTop(scrollTop) {
          // do some minimal validations on scrollTop
          const scrollDimensions = this._scrollable.getScrollDimensions();
          if (scrollTop + scrollDimensions.height > scrollDimensions.scrollHeight) {
              scrollTop = scrollDimensions.scrollHeight - scrollDimensions.height;
          }
          if (scrollTop < 0) {
              scrollTop = 0;
          }
          return this._linesLayout.getLinesViewportData(scrollTop, scrollTop + scrollDimensions.height);
      }
      getWhitespaceViewportData() {
          const visibleBox = this.getCurrentViewport();
          return this._linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height);
      }
      getWhitespaces() {
          return this._linesLayout.getWhitespaces();
      }
      // ---- IScrollingProvider
      getContentWidth() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          return scrollDimensions.contentWidth;
      }
      getScrollWidth() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          return scrollDimensions.scrollWidth;
      }
      getContentHeight() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          return scrollDimensions.contentHeight;
      }
      getScrollHeight() {
          const scrollDimensions = this._scrollable.getScrollDimensions();
          return scrollDimensions.scrollHeight;
      }
      getCurrentScrollLeft() {
          const currentScrollPosition = this._scrollable.getCurrentScrollPosition();
          return currentScrollPosition.scrollLeft;
      }
      getCurrentScrollTop() {
          const currentScrollPosition = this._scrollable.getCurrentScrollPosition();
          return currentScrollPosition.scrollTop;
      }
      validateScrollPosition(scrollPosition) {
          return this._scrollable.validateScrollPosition(scrollPosition);
      }
      setScrollPosition(position, type) {
          if (type === 1 /* Immediate */) {
              this._scrollable.setScrollPositionNow(position);
          }
          else {
              this._scrollable.setScrollPositionSmooth(position);
          }
      }
      deltaScrollNow(deltaScrollLeft, deltaScrollTop) {
          const currentScrollPosition = this._scrollable.getCurrentScrollPosition();
          this._scrollable.setScrollPositionNow({
              scrollLeft: currentScrollPosition.scrollLeft + deltaScrollLeft,
              scrollTop: currentScrollPosition.scrollTop + deltaScrollTop
          });
      }
  }
  