From 5a1565cefefba0e334f65d9b40b364e5ab5976ab Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 25 May 2020 09:55:49 +0200 Subject: [PATCH] Move scroll event emitting through view model (fixes #97447) --- src/vs/base/common/scrollable.ts | 16 +++ src/vs/editor/browser/view/viewImpl.ts | 9 -- .../editor/browser/view/viewOutgoingEvents.ts | 23 ---- .../editor/browser/widget/codeEditorWidget.ts | 13 ++- .../viewModel/viewModelEventDispatcher.ts | 100 +++++++++++++++++- .../editor/common/viewModel/viewModelImpl.ts | 7 +- 6 files changed, 126 insertions(+), 42 deletions(-) diff --git a/src/vs/base/common/scrollable.ts b/src/vs/base/common/scrollable.ts index c507366e853..a45e0763ab1 100644 --- a/src/vs/base/common/scrollable.ts +++ b/src/vs/base/common/scrollable.ts @@ -13,10 +13,18 @@ export const enum ScrollbarVisibility { } export interface ScrollEvent { + oldWidth: number; + oldScrollWidth: number; + oldScrollLeft: number; + width: number; scrollWidth: number; scrollLeft: number; + oldHeight: number; + oldScrollHeight: number; + oldScrollTop: number; + height: number; scrollHeight: number; scrollTop: number; @@ -134,10 +142,18 @@ export class ScrollState implements IScrollDimensions, IScrollPosition { const scrollTopChanged = (this.scrollTop !== previous.scrollTop); return { + oldWidth: previous.width, + oldScrollWidth: previous.scrollWidth, + oldScrollLeft: previous.scrollLeft, + width: this.width, scrollWidth: this.scrollWidth, scrollLeft: this.scrollLeft, + oldHeight: previous.height, + oldScrollHeight: previous.scrollHeight, + oldScrollTop: previous.scrollTop, + height: this.height, scrollHeight: this.scrollHeight, scrollTop: this.scrollTop, diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 19eb4fc14a5..d58c3f0fede 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -305,15 +305,6 @@ export class View extends ViewEventHandler { } public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { this.domNode.setClassName(this.getEditorClassName()); - if (e.isFocused) { - this.outgoingEvents.emitViewFocusGained(); - } else { - this.outgoingEvents.emitViewFocusLost(); - } - return false; - } - public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { - this.outgoingEvents.emitScrollChanged(e); return false; } public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { diff --git a/src/vs/editor/browser/view/viewOutgoingEvents.ts b/src/vs/editor/browser/view/viewOutgoingEvents.ts index 0c6e7c16615..2c7fa1db33b 100644 --- a/src/vs/editor/browser/view/viewOutgoingEvents.ts +++ b/src/vs/editor/browser/view/viewOutgoingEvents.ts @@ -9,8 +9,6 @@ import { MouseTarget } from 'vs/editor/browser/controller/mouseTarget'; import { IEditorMouseEvent, IMouseTarget, IPartialEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IScrollEvent } from 'vs/editor/common/editorCommon'; -import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -20,9 +18,6 @@ export interface EventCallback { export class ViewOutgoingEvents extends Disposable { - public onDidScroll: EventCallback | null = null; - public onDidGainFocus: EventCallback | null = null; - public onDidLoseFocus: EventCallback | null = null; public onKeyDown: EventCallback | null = null; public onKeyUp: EventCallback | null = null; public onContextMenu: EventCallback | null = null; @@ -41,24 +36,6 @@ export class ViewOutgoingEvents extends Disposable { this._viewModel = viewModel; } - public emitScrollChanged(e: viewEvents.ViewScrollChangedEvent): void { - if (this.onDidScroll) { - this.onDidScroll(e); - } - } - - public emitViewFocusGained(): void { - if (this.onDidGainFocus) { - this.onDidGainFocus(undefined); - } - } - - public emitViewFocusLost(): void { - if (this.onDidLoseFocus) { - this.onDidLoseFocus(undefined); - } - } - public emitKeyDown(e: IKeyboardEvent): void { if (this.onKeyDown) { this.onKeyDown(e); diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 592dde96f89..0f3aaa1bddf 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1515,6 +1515,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE case OutgoingViewModelEventKind.ContentSizeChanged: this._onDidContentSizeChange.fire(e); break; + case OutgoingViewModelEventKind.FocusChanged: + this._editorTextFocus.setValue(e.hasFocus); + break; + case OutgoingViewModelEventKind.ScrollChanged: + this._onDidScrollChange.fire(e); + break; } })); @@ -1596,14 +1602,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE }; } - const onDidChangeTextFocus = (textFocus: boolean) => { - this._editorTextFocus.setValue(textFocus); - }; - const viewOutgoingEvents = new ViewOutgoingEvents(viewModel); - viewOutgoingEvents.onDidScroll = (e) => this._onDidScrollChange.fire(e); - viewOutgoingEvents.onDidGainFocus = () => onDidChangeTextFocus(true); - viewOutgoingEvents.onDidLoseFocus = () => onDidChangeTextFocus(false); viewOutgoingEvents.onKeyDown = (e) => this._onKeyDown.fire(e); viewOutgoingEvents.onKeyUp = (e) => this._onKeyUp.fire(e); viewOutgoingEvents.onContextMenu = (e) => this._onContextMenu.fire(e); diff --git a/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts b/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts index 64bcbf65f67..2bd933331e7 100644 --- a/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts +++ b/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts @@ -54,6 +54,9 @@ export class ViewModelEventDispatcher extends Disposable { return; } const event = this._outgoingEvents.shift()!; + if (event.isNoOp()) { + continue; + } this._onEvent.fire(event); } } @@ -143,6 +146,8 @@ export class ViewModelEventDispatcher extends Disposable { export const enum OutgoingViewModelEventKind { ContentSizeChanged, + FocusChanged, + ScrollChanged, } export class ContentSizeChangedEvent implements IContentSizeChangedEvent { @@ -166,9 +171,100 @@ export class ContentSizeChangedEvent implements IContentSizeChangedEvent { this.contentHeightChanged = (this._oldContentHeight !== this.contentHeight); } - public merge(other: ContentSizeChangedEvent): ContentSizeChangedEvent { + public isNoOp(): boolean { + return (!this.contentWidthChanged && !this.contentHeightChanged); + } + + + public merge(other: OutgoingViewModelEvent): ContentSizeChangedEvent { + if (other.kind !== OutgoingViewModelEventKind.ContentSizeChanged) { + return this; + } return new ContentSizeChangedEvent(this._oldContentWidth, this._oldContentHeight, other.contentWidth, other.contentHeight); } } -export type OutgoingViewModelEvent = ContentSizeChangedEvent; +export class FocusChangedEvent { + + public readonly kind = OutgoingViewModelEventKind.FocusChanged; + + readonly oldHasFocus: boolean; + readonly hasFocus: boolean; + + constructor(oldHasFocus: boolean, hasFocus: boolean) { + this.oldHasFocus = oldHasFocus; + this.hasFocus = hasFocus; + } + + public isNoOp(): boolean { + return (this.oldHasFocus === this.hasFocus); + } + + public merge(other: OutgoingViewModelEvent): FocusChangedEvent { + if (other.kind !== OutgoingViewModelEventKind.FocusChanged) { + return this; + } + return new FocusChangedEvent(this.oldHasFocus, other.hasFocus); + } +} + +export class ScrollChangedEvent { + + public readonly kind = OutgoingViewModelEventKind.ScrollChanged; + + private readonly _oldScrollWidth: number; + private readonly _oldScrollLeft: number; + private readonly _oldScrollHeight: number; + private readonly _oldScrollTop: number; + + public readonly scrollWidth: number; + public readonly scrollLeft: number; + public readonly scrollHeight: number; + public readonly scrollTop: number; + + public readonly scrollWidthChanged: boolean; + public readonly scrollLeftChanged: boolean; + public readonly scrollHeightChanged: boolean; + public readonly scrollTopChanged: boolean; + + constructor( + oldScrollWidth: number, oldScrollLeft: number, oldScrollHeight: number, oldScrollTop: number, + scrollWidth: number, scrollLeft: number, scrollHeight: number, scrollTop: number, + ) { + this._oldScrollWidth = oldScrollWidth; + this._oldScrollLeft = oldScrollLeft; + this._oldScrollHeight = oldScrollHeight; + this._oldScrollTop = oldScrollTop; + + this.scrollWidth = scrollWidth; + this.scrollLeft = scrollLeft; + this.scrollHeight = scrollHeight; + this.scrollTop = scrollTop; + + this.scrollWidthChanged = (this._oldScrollWidth !== this.scrollWidth); + this.scrollLeftChanged = (this._oldScrollLeft !== this.scrollLeft); + this.scrollHeightChanged = (this._oldScrollHeight !== this.scrollHeight); + this.scrollTopChanged = (this._oldScrollTop !== this.scrollTop); + } + + public isNoOp(): boolean { + return (!this.scrollWidthChanged && !this.scrollLeftChanged && !this.scrollHeightChanged && !this.scrollTopChanged); + } + + + public merge(other: OutgoingViewModelEvent): ScrollChangedEvent { + if (other.kind !== OutgoingViewModelEventKind.ScrollChanged) { + return this; + } + return new ScrollChangedEvent( + this._oldScrollWidth, this._oldScrollLeft, this._oldScrollHeight, this._oldScrollTop, + other.scrollWidth, other.scrollLeft, other.scrollHeight, other.scrollTop + ); + } +} + +export type OutgoingViewModelEvent = ( + ContentSizeChangedEvent + | FocusChangedEvent + | ScrollChangedEvent +); diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index fc5814ba3f0..99de87ae6ab 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -30,7 +30,7 @@ import { Cursor } from 'vs/editor/common/controller/cursor'; import { PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; -import { ViewModelEventDispatcher, OutgoingViewModelEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher'; +import { ViewModelEventDispatcher, OutgoingViewModelEvent, FocusChangedEvent, ScrollChangedEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; const USE_IDENTITY_LINES_COLLECTION = true; @@ -112,6 +112,10 @@ export class ViewModel extends Disposable implements IViewModel { this._tokenizeViewportSoon.schedule(); } this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewScrollChangedEvent(e)); + this._eventDispatcher.emitOutgoingEvent(new ScrollChangedEvent( + e.oldScrollWidth, e.oldScrollLeft, e.oldScrollHeight, e.oldScrollTop, + e.scrollWidth, e.scrollLeft, e.scrollHeight, e.scrollTop + )); })); this._register(this.viewLayout.onDidContentSizeChange((e) => { @@ -172,6 +176,7 @@ export class ViewModel extends Disposable implements IViewModel { this.hasFocus = hasFocus; this.cursor.setHasFocus(hasFocus); this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewFocusChangedEvent(hasFocus)); + this._eventDispatcher.emitOutgoingEvent(new FocusChangedEvent(!hasFocus, hasFocus)); } public onDidColorThemeChange(): void { -- GitLab