123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*---------------------------------------------------------------------------------------------
- * 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.js';
- import { Disposable } from '../../../base/common/lifecycle.js';
- import { Scrollable } from '../../../base/common/scrollable.js';
- import { LinesLayout } from './linesLayout.js';
- import { Viewport } from '../viewModel/viewModel.js';
- import { ContentSizeChangedEvent } from '../viewModel/viewModelEventDispatcher.js';
- 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(130 /* layoutInfo */);
- const padding = options.get(74 /* padding */);
- this._linesLayout = new LinesLayout(lineCount, options.get(58 /* 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(102 /* smoothScrolling */) ? SMOOTH_SCROLLING_TIME : 0);
- }
- // ---- begin view event handlers
- onConfigurationChanged(e) {
- const options = this._configuration.options;
- if (e.hasChanged(58 /* lineHeight */)) {
- this._linesLayout.setLineHeight(options.get(58 /* lineHeight */));
- }
- if (e.hasChanged(74 /* padding */)) {
- const padding = options.get(74 /* padding */);
- this._linesLayout.setPadding(padding.top, padding.bottom);
- }
- if (e.hasChanged(130 /* layoutInfo */)) {
- const layoutInfo = options.get(130 /* 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(102 /* 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(91 /* 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(93 /* scrollBeyondLastLine */)) {
- result += Math.max(0, height - options.get(58 /* lineHeight */) - options.get(74 /* 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(131 /* wrappingInfo */);
- const fontInfo = options.get(43 /* fontInfo */);
- if (wrappingInfo.isViewportWrapping) {
- const layoutInfo = options.get(130 /* layoutInfo */);
- const minimap = options.get(64 /* 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(92 /* 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();
- let scrollTop = currentScrollPosition.scrollTop;
- let firstLineNumberInViewport = this._linesLayout.getLineNumberAtOrAfterVerticalOffset(scrollTop);
- let 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
- });
- }
- }
|