viewOverlays.ts 8.4 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

A
Alex Dima 已提交
7 8
import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
A
Alex Dima 已提交
9
import {StyleMutator} from 'vs/base/browser/styleMutator';
A
Alex Dima 已提交
10 11 12
import {IConfigurationChangedEvent, IEditorLayoutInfo, IModelDecoration, IScrollEvent} from 'vs/editor/common/editorCommon';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import {IVisibleLineData, ViewLayer} from 'vs/editor/browser/view/viewLayer';
E
Erich Gamma 已提交
13 14

export class ViewOverlays extends ViewLayer {
A
Alex Dima 已提交
15
	private _dynamicOverlays:editorBrowser.IDynamicViewOverlay[];
E
Erich Gamma 已提交
16

A
Alex Dima 已提交
17
	_layoutProvider:editorBrowser.ILayoutProvider;
E
Erich Gamma 已提交
18

A
Alex Dima 已提交
19
	constructor(context:editorBrowser.IViewContext, layoutProvider:editorBrowser.ILayoutProvider) {
E
Erich Gamma 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
		super(context);

		this._layoutProvider = layoutProvider;
		this._dynamicOverlays = [];

		this.domNode.className = 'view-overlays';

	}

	public dispose(): void {
		super.dispose();
		this._layoutProvider = null;

		for(var i = 0; i < this._dynamicOverlays.length; i++) {
			this._dynamicOverlays[i].dispose();
		}
		this._dynamicOverlays = null;
	}

	public getDomNode(): HTMLElement {
		return this.domNode;
	}

A
Alex Dima 已提交
43
	public addDynamicOverlay(overlay:editorBrowser.IDynamicViewOverlay): void {
E
Erich Gamma 已提交
44 45 46 47 48 49 50
		this._dynamicOverlays.push(overlay);
	}

	// ----- event handlers

	public onViewFocusChanged(isFocused:boolean): boolean {
		this._requestModificationFrame(() => {
A
Alex Dima 已提交
51
			dom.toggleClass(this.domNode, 'focused', isFocused);
E
Erich Gamma 已提交
52 53 54 55 56 57 58 59 60 61 62 63
		});
		return false;
	}

	// ----- end event handlers

	_createLine(): IVisibleLineData {
		var r = new ViewOverlayLine(this._context, this._dynamicOverlays);
		return r;
	}


A
Alex Dima 已提交
64
	public onReadAfterForcedLayout(ctx:editorBrowser.IRenderingContext): void {
E
Erich Gamma 已提交
65 66 67 68 69 70 71 72 73 74 75 76
		// Overwriting to bypass `shouldRender` flag
		for (var i = 0; i < this._dynamicOverlays.length; i++) {
			this._dynamicOverlays[i].shouldCallRender2(ctx);
		}

		this._requestModificationFrame(() => {
			this._viewOverlaysRender(ctx);
		});

		return null;
	}

A
Alex Dima 已提交
77
	_viewOverlaysRender(ctx:editorBrowser.IRestrictedRenderingContext): void {
E
Erich Gamma 已提交
78 79 80 81 82 83 84 85 86 87 88
		super._renderLines(ctx.linesViewportData);
	}

	public onWriteAfterForcedLayout(): void {
		// Overwriting to bypass `shouldRender` flag
		this._executeModificationRunners();
	}
}

class ViewOverlayLine implements IVisibleLineData {

A
Alex Dima 已提交
89 90
	private _context:editorBrowser.IViewContext;
	private _dynamicOverlays:editorBrowser.IDynamicViewOverlay[];
E
Erich Gamma 已提交
91 92 93
	private _domNode: HTMLElement;
	private _renderPieces: string[];

A
Alex Dima 已提交
94
	constructor(context:editorBrowser.IViewContext, dynamicOverlays:editorBrowser.IDynamicViewOverlay[]) {
E
Erich Gamma 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
		this._context = context;
		this._dynamicOverlays = dynamicOverlays;

		this._domNode = null;
		this._renderPieces = null;
	}

	public getDomNode(): HTMLElement {
		return this._domNode;
	}
	public setDomNode(domNode:HTMLElement): void {
		this._domNode = domNode;
	}

	onContentChanged(): void {
		// Nothing
	}
	onLinesInsertedAbove(): void {
		// Nothing
	}
	onLinesDeletedAbove(): void {
		// Nothing
	}
	onLineChangedAbove(): void {
		// Nothing
	}
	onTokensChanged(): void {
		// Nothing
	}
A
Alex Dima 已提交
124
	onConfigurationChanged(e:IConfigurationChangedEvent): void {
E
Erich Gamma 已提交
125 126 127 128
		// Nothing
	}

	private _piecesEqual(newPieces: string[]): boolean {
A
Alex Dima 已提交
129
		if (!this._renderPieces) {
E
Erich Gamma 已提交
130 131
			return false;
		}
A
Alex Dima 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144

		let myLen = this._renderPieces.length;
		let newLen = newPieces.length;

		if (myLen !== newLen) {
			return false;
		}

		if (newLen === 0) {
			return true;
		}

		for (let i = 0; i < newLen; i++) {
E
Erich Gamma 已提交
145 146 147 148
			if (this._renderPieces[i] !== newPieces[i]) {
				return false;
			}
		}
A
Alex Dima 已提交
149

E
Erich Gamma 已提交
150 151 152
		return true;
	}

A
Alex Dima 已提交
153
	shouldUpdateHTML(lineNumber:number, inlineDecorations:IModelDecoration[]): boolean {
E
Erich Gamma 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
		var newPieces: string[] = [];
		for (var i = 0; i < this._dynamicOverlays.length; i++) {
			var pieces = this._dynamicOverlays[i].render2(lineNumber);
			if (pieces && pieces.length > 0) {
				newPieces = newPieces.concat(pieces);
			}
		}

		var piecesEqual = this._piecesEqual(newPieces);
		if (!piecesEqual) {
			this._renderPieces = newPieces;
		}

		return !piecesEqual;
	}

	getLineOuterHTML(out:string[], lineNumber:number, deltaTop:number): void {
		out.push('<div lineNumber="');
		out.push(lineNumber.toString());
		out.push('" style="top:');
		out.push(deltaTop.toString());
		out.push('px;height:');
		out.push(this._context.configuration.editor.lineHeight.toString());
		out.push('px;" class="');
A
Alex Dima 已提交
178
		out.push(editorBrowser.ClassNames.VIEW_LINE);
E
Erich Gamma 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192
		out.push('">');
		out.push(this.getLineInnerHTML(lineNumber));
		out.push('</div>');
	}

	getLineInnerHTML(lineNumber: number): string {
		return this._renderPieces.join('');
	}

	layoutLine(lineNumber: number, deltaTop:number): void {
		var currentLineNumber = this._domNode.getAttribute('lineNumber');
		if (currentLineNumber !== lineNumber.toString()) {
			this._domNode.setAttribute('lineNumber', lineNumber.toString());
		}
A
Alex Dima 已提交
193 194
		StyleMutator.setTop(this._domNode, deltaTop);
		StyleMutator.setHeight(this._domNode, this._context.configuration.editor.lineHeight);
E
Erich Gamma 已提交
195 196 197 198 199
	}
}

export class ContentViewOverlays extends ViewOverlays {

A
Alex Dima 已提交
200
	constructor(context:editorBrowser.IViewContext, layoutProvider:editorBrowser.ILayoutProvider) {
E
Erich Gamma 已提交
201 202
		super(context, layoutProvider);

A
Alex Dima 已提交
203 204
		StyleMutator.setWidth(this.domNode, 0);
		StyleMutator.setHeight(this.domNode, 0);
E
Erich Gamma 已提交
205 206 207 208 209 210
	}

	public onScrollWidthChanged(scrollWidth:number): boolean {
		return true;
	}

A
Alex Dima 已提交
211
	_viewOverlaysRender(ctx:editorBrowser.IRestrictedRenderingContext): void {
E
Erich Gamma 已提交
212 213
		super._viewOverlaysRender(ctx);

A
Alex Dima 已提交
214
		StyleMutator.setWidth(this.domNode, this._layoutProvider.getScrollWidth());
E
Erich Gamma 已提交
215 216 217 218 219 220 221 222 223
	}
}

export class MarginViewOverlays extends ViewOverlays {

	private _glyphMarginLeft:number;
	private _glyphMarginWidth:number;
	private _scrollHeight:number;

A
Alex Dima 已提交
224
	constructor(context:editorBrowser.IViewContext, layoutProvider:editorBrowser.ILayoutProvider) {
E
Erich Gamma 已提交
225 226 227 228 229 230
		super(context, layoutProvider);

		this._glyphMarginLeft = 0;
		this._glyphMarginWidth = 0;
		this._scrollHeight = layoutProvider.getScrollHeight();

A
Alex Dima 已提交
231
		this.domNode.className = editorBrowser.ClassNames.MARGIN_VIEW_OVERLAYS + ' monaco-editor-background';
A
Alex Dima 已提交
232
		StyleMutator.setWidth(this.domNode, 1);
E
Erich Gamma 已提交
233 234 235 236 237 238
		this._hasVerticalScroll = true;
	}

	protected _extraDomNodeHTML(): string {
		return [
			'<div class="',
A
Alex Dima 已提交
239
			editorBrowser.ClassNames.GLYPH_MARGIN,
E
Erich Gamma 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
			'" style="left:',
			String(this._glyphMarginLeft),
			'px;width:',
			String(this._glyphMarginWidth),
			'px;height:',
			String(this._scrollHeight),
			'px;"></div>'
		].join('');
	}

	private _getGlyphMarginDomNode(): HTMLElement {
		return <HTMLElement>this.domNode.children[0];
	}

	public onScrollHeightChanged(scrollHeight:number): boolean {
		this._scrollHeight = scrollHeight;
		this._requestModificationFrame(() => {
			var glyphMargin = this._getGlyphMarginDomNode();
			if (glyphMargin) {
A
Alex Dima 已提交
259
				StyleMutator.setHeight(glyphMargin, this._scrollHeight);
E
Erich Gamma 已提交
260 261 262 263 264
			}
		});
		return super.onScrollHeightChanged(scrollHeight) || true;
	}

A
Alex Dima 已提交
265
	public onLayoutChanged(layoutInfo:IEditorLayoutInfo): boolean {
E
Erich Gamma 已提交
266 267 268 269 270
		this._glyphMarginLeft = layoutInfo.glyphMarginLeft;
		this._glyphMarginWidth = layoutInfo.glyphMarginWidth;
		this._scrollHeight = this._layoutProvider.getScrollHeight();

		this._requestModificationFrame(() => {
A
Alex Dima 已提交
271
			StyleMutator.setWidth(this.domNode, layoutInfo.contentLeft);
E
Erich Gamma 已提交
272 273 274

			var glyphMargin = this._getGlyphMarginDomNode();
			if (glyphMargin) {
A
Alex Dima 已提交
275 276
				StyleMutator.setLeft(glyphMargin, layoutInfo.glyphMarginLeft);
				StyleMutator.setWidth(glyphMargin, layoutInfo.glyphMarginWidth);
E
Erich Gamma 已提交
277 278 279 280 281 282
			}
		});
		return super.onLayoutChanged(layoutInfo) || true;
	}

	private _hasVerticalScroll = false;
A
Alex Dima 已提交
283
	public onScrollChanged(e:IScrollEvent): boolean {
E
Erich Gamma 已提交
284 285 286 287
		this._hasVerticalScroll = this._hasVerticalScroll || e.vertical;
		return super.onScrollChanged(e);
	}

A
Alex Dima 已提交
288
	_viewOverlaysRender(ctx:editorBrowser.IRestrictedRenderingContext): void {
E
Erich Gamma 已提交
289 290
		super._viewOverlaysRender(ctx);
		if (this._hasVerticalScroll) {
A
Alex Dima 已提交
291
			if (browser.canUseTranslate3d) {
E
Erich Gamma 已提交
292
				var transform = 'translate3d(0px, ' + ctx.linesViewportData.visibleRangesDeltaTop + 'px, 0px)';
A
Alex Dima 已提交
293
				StyleMutator.setTransform(this.domNode, transform);
E
Erich Gamma 已提交
294 295
			} else {
				if (this._hasVerticalScroll) {
A
Alex Dima 已提交
296
					StyleMutator.setTop(this.domNode, ctx.linesViewportData.visibleRangesDeltaTop);
E
Erich Gamma 已提交
297 298 299 300 301
				}
			}
			this._hasVerticalScroll = false;
		}
		var height = Math.min(this._layoutProvider.getTotalHeight(), 1000000);
A
Alex Dima 已提交
302
		StyleMutator.setHeight(this.domNode, height);
E
Erich Gamma 已提交
303 304
	}
}