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

'use strict';

import 'vs/css!./viewCursors';
A
Alex Dima 已提交
9 10
import * as browser from 'vs/base/browser/browser';
import * as editorCommon from 'vs/editor/common/editorCommon';
11
import {ClassNames} from 'vs/editor/browser/editorBrowser';
E
Erich Gamma 已提交
12
import {ViewPart} from 'vs/editor/browser/view/viewPart';
A
Alex Dima 已提交
13
import {ViewCursor} from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
A
Alex Dima 已提交
14
import {ViewContext} from 'vs/editor/common/view/viewContext';
15
import {IRenderingContext, IRestrictedRenderingContext} from 'vs/editor/common/view/renderingContext';
16
import {FastDomNode, createFastDomNode} from 'vs/base/browser/styleMutator';
E
Erich Gamma 已提交
17 18 19 20 21 22 23 24 25 26 27

enum RenderType {
	Hidden,
	Visible,
	Blink
}

export class ViewCursors extends ViewPart {

	static BLINK_INTERVAL = 500;

A
Alex Dima 已提交
28 29 30
	private _readOnly: boolean;
	private _cursorBlinking: string;
	private _cursorStyle: editorCommon.TextEditorCursorStyle;
A
Alex Dima 已提交
31

A
Alex Dima 已提交
32
	private _isVisible: boolean;
E
Erich Gamma 已提交
33

34
	private _domNode: FastDomNode;
E
Erich Gamma 已提交
35

A
Alex Dima 已提交
36
	private _blinkTimer: number;
E
Erich Gamma 已提交
37

A
Alex Dima 已提交
38
	private _editorHasFocus: boolean;
E
Erich Gamma 已提交
39 40 41 42

	private _primaryCursor: ViewCursor;
	private _secondaryCursors: ViewCursor[];

A
Alex Dima 已提交
43
	constructor(context: ViewContext) {
E
Erich Gamma 已提交
44 45
		super(context);

A
Alex Dima 已提交
46 47 48 49
		this._readOnly = this._context.configuration.editor.readOnly;
		this._cursorBlinking = this._context.configuration.editor.cursorBlinking;
		this._cursorStyle = this._context.configuration.editor.cursorStyle;

E
Erich Gamma 已提交
50 51 52
		this._primaryCursor = new ViewCursor(this._context, false);
		this._secondaryCursors = [];

53
		this._domNode = createFastDomNode(document.createElement('div'));
54
		this._updateDomClassName();
E
Erich Gamma 已提交
55

56
		this._domNode.domNode.appendChild(this._primaryCursor.getDomNode());
E
Erich Gamma 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

		this._blinkTimer = -1;

		this._editorHasFocus = false;
		this._updateBlinking();
	}

	public dispose(): void {
		super.dispose();
		if (this._blinkTimer !== -1) {
			window.clearInterval(this._blinkTimer);
			this._blinkTimer = -1;
		}
	}

	public getDomNode(): HTMLElement {
73
		return this._domNode.domNode;
E
Erich Gamma 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86
	}

	// --- begin event handlers

	public onModelFlushed(): boolean {
		this._primaryCursor.onModelFlushed();
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			var domNode = this._secondaryCursors[i].getDomNode();
			domNode.parentNode.removeChild(domNode);
		}
		this._secondaryCursors = [];
		return true;
	}
A
Alex Dima 已提交
87
	public onModelDecorationsChanged(e: editorCommon.IViewDecorationsChangedEvent): boolean {
E
Erich Gamma 已提交
88 89 90
		// true for inline decorations that can end up relayouting text
		return e.inlineDecorationsChanged;
	}
A
Alex Dima 已提交
91
	public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): boolean {
E
Erich Gamma 已提交
92 93
		return true;
	}
A
Alex Dima 已提交
94
	public onModelLineChanged(e: editorCommon.IViewLineChangedEvent): boolean {
E
Erich Gamma 已提交
95 96
		return true;
	}
A
Alex Dima 已提交
97
	public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): boolean {
E
Erich Gamma 已提交
98 99
		return true;
	}
A
Alex Dima 已提交
100 101
	public onModelTokensChanged(e: editorCommon.IViewTokensChangedEvent): boolean {
		var shouldRender = (position: editorCommon.IPosition) => {
E
Erich Gamma 已提交
102 103 104 105 106 107 108 109 110 111 112 113
			return e.fromLineNumber <= position.lineNumber && position.lineNumber <= e.toLineNumber;
		};
		if (shouldRender(this._primaryCursor.getPosition())) {
			return true;
		}
		for (var i = 0; i < this._secondaryCursors.length; i++) {
			if (shouldRender(this._secondaryCursors[i].getPosition())) {
				return true;
			}
		}
		return false;
	}
A
Alex Dima 已提交
114
	public onCursorPositionChanged(e: editorCommon.IViewCursorPositionChangedEvent): boolean {
E
Erich Gamma 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
		this._primaryCursor.onCursorPositionChanged(e.position, e.isInEditableRange);
		this._updateBlinking();

		if (this._secondaryCursors.length < e.secondaryPositions.length) {
			// Create new cursors
			var addCnt = e.secondaryPositions.length - this._secondaryCursors.length;
			for (var i = 0; i < addCnt; i++) {
				var newCursor = new ViewCursor(this._context, true);
				this._primaryCursor.getDomNode().parentNode.insertBefore(newCursor.getDomNode(), this._primaryCursor.getDomNode().nextSibling);
				this._secondaryCursors.push(newCursor);
			}
		} else if (this._secondaryCursors.length > e.secondaryPositions.length) {
			// Remove some cursors
			var removeCnt = this._secondaryCursors.length - e.secondaryPositions.length;
			for (var i = 0; i < removeCnt; i++) {
				this._secondaryCursors[0].getDomNode().parentNode.removeChild(this._secondaryCursors[0].getDomNode());
				this._secondaryCursors.splice(0, 1);
			}
		}

		for (var i = 0; i < e.secondaryPositions.length; i++) {
			this._secondaryCursors[i].onCursorPositionChanged(e.secondaryPositions[i], e.isInEditableRange);
		}

		return true;
	}
A
Alex Dima 已提交
141
	public onCursorSelectionChanged(e: editorCommon.IViewCursorSelectionChangedEvent): boolean {
E
Erich Gamma 已提交
142 143
		return false;
	}
A
Alex Dima 已提交
144
	public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
A
Alex Dima 已提交
145 146 147 148 149 150 151 152 153 154 155

		if (e.readOnly) {
			this._readOnly = this._context.configuration.editor.readOnly;
		}
		if (e.cursorBlinking) {
			this._cursorBlinking = this._context.configuration.editor.cursorBlinking;
		}
		if (e.cursorStyle) {
			this._cursorStyle = this._context.configuration.editor.cursorStyle;
		}

E
Erich Gamma 已提交
156
		this._primaryCursor.onConfigurationChanged(e);
157
		this._updateBlinking();
158 159 160
		if (e.cursorStyle) {
			this._updateDomClassName();
		}
E
Erich Gamma 已提交
161 162 163 164 165
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			this._secondaryCursors[i].onConfigurationChanged(e);
		}
		return true;
	}
A
Alex Dima 已提交
166
	public onLayoutChanged(layoutInfo: editorCommon.IEditorLayoutInfo): boolean {
E
Erich Gamma 已提交
167 168
		return true;
	}
A
Alex Dima 已提交
169
	public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
E
Erich Gamma 已提交
170 171 172 173 174
		return true;
	}
	public onZonesChanged(): boolean {
		return true;
	}
A
Alex Dima 已提交
175
	public onViewFocusChanged(isFocused: boolean): boolean {
E
Erich Gamma 已提交
176 177 178 179 180 181
		this._editorHasFocus = isFocused;
		this._updateBlinking();
		return false;
	}
	// --- end event handlers

A
Alex Dima 已提交
182
	public getPosition(): editorCommon.IPosition {
E
Erich Gamma 已提交
183 184 185
		return this._primaryCursor.getPosition();
	}

A
Alex Dima 已提交
186
	// ---- blinking logic
E
Erich Gamma 已提交
187 188 189

	private _getRenderType(): RenderType {
		if (this._editorHasFocus) {
A
Alex Dima 已提交
190 191
			if (this._primaryCursor.getIsInEditableRange() && !this._readOnly) {
				switch (this._cursorBlinking) {
J
Joao Moreno 已提交
192
					case 'blink':
193
						return RenderType.Blink;
J
Joao Moreno 已提交
194
					case 'visible':
195
						return RenderType.Visible;
J
Joao Moreno 已提交
196
					case 'hidden':
197 198 199 200
						return RenderType.Hidden;
					default:
						return RenderType.Blink;
				}
E
Erich Gamma 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
			}
			return RenderType.Visible;
		}
		return RenderType.Hidden;
	}

	private _updateBlinking(): void {
		if (this._blinkTimer !== -1) {
			window.clearInterval(this._blinkTimer);
			this._blinkTimer = -1;
		}

		var renderType = this._getRenderType();

		if (renderType === RenderType.Visible || renderType === RenderType.Blink) {
			this._show();
		} else {
			this._hide();
		}

		if (renderType === RenderType.Blink) {
			this._blinkTimer = window.setInterval(() => this._blink(), ViewCursors.BLINK_INTERVAL);
		}
	}
A
Alex Dima 已提交
225
	// --- end blinking logic
E
Erich Gamma 已提交
226

227
	private _updateDomClassName(): void {
228
		this._domNode.setClassName(this._getClassName());
M
markrendle 已提交
229 230
	}

231
	private _getClassName(): string {
A
Alex Dima 已提交
232
		let result = ClassNames.VIEW_CURSORS_LAYER;
233
		let extraClassName: string;
A
Alex Dima 已提交
234
		switch (this._cursorStyle) {
A
Alex Dima 已提交
235
			case editorCommon.TextEditorCursorStyle.Line:
236 237
				extraClassName = 'cursor-line-style';
				break;
A
Alex Dima 已提交
238
			case editorCommon.TextEditorCursorStyle.Block:
239 240
				extraClassName = 'cursor-block-style';
				break;
A
Alex Dima 已提交
241 242 243
			case editorCommon.TextEditorCursorStyle.Underline:
				extraClassName = 'cursor-underline-style';
				break;
244 245 246 247
			default:
				extraClassName = 'cursor-line-style';
		}
		return result + ' ' + extraClassName;
M
markrendle 已提交
248 249
	}

E
Erich Gamma 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	private _blink(): void {
		if (this._isVisible) {
			this._hide();
		} else {
			this._show();
		}
	}

	private _show(): void {
		this._primaryCursor.show();
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			this._secondaryCursors[i].show();
		}
		this._isVisible = true;
	}

	private _hide(): void {
		this._primaryCursor.hide();
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			this._secondaryCursors[i].hide();
		}
		this._isVisible = false;
	}

	// ---- IViewPart implementation

A
Alex Dima 已提交
276 277 278 279 280
	public prepareRender(ctx: IRenderingContext): void {
		if (!this.shouldRender()) {
			throw new Error('I did not ask to render!');
		}

E
Erich Gamma 已提交
281 282 283 284
		this._primaryCursor.prepareRender(ctx);
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			this._secondaryCursors[i].prepareRender(ctx);
		}
A
Alex Dima 已提交
285
	}
E
Erich Gamma 已提交
286

A
Alex Dima 已提交
287 288 289 290 291
	public render(ctx: IRestrictedRenderingContext): void {
		this._primaryCursor.render(ctx);
		for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
			this._secondaryCursors[i].render(ctx);
		}
292 293 294 295 296 297

		if (browser.canUseTranslate3d) {
			this._domNode.setTransform('translate3d(0px, 0px, 0px)');
		} else {
			this._domNode.setTransform('');
		}
E
Erich Gamma 已提交
298 299
	}
}