sash.ts 6.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!./sash';
J
Joao Moreno 已提交
9
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
B
Benjamin Pasero 已提交
10 11
import {Builder, $} from 'vs/base/browser/builder';
import {isIPad} from 'vs/base/browser/browser';
B
Benjamin Pasero 已提交
12
import {isMacintosh} from 'vs/base/common/platform';
B
Benjamin Pasero 已提交
13
import types = require('vs/base/common/types');
E
Erich Gamma 已提交
14
import DOM = require('vs/base/browser/dom');
B
Benjamin Pasero 已提交
15 16 17
import {Gesture, EventType, GestureEvent} from 'vs/base/browser/touch';
import {EventEmitter} from 'vs/base/common/eventEmitter';
import {StandardMouseEvent} from 'vs/base/browser/mouseEvent';
E
Erich Gamma 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

export interface ISashLayoutProvider { }

export interface IVerticalSashLayoutProvider extends ISashLayoutProvider {
	getVerticalSashLeft(sash: Sash): number;
	getVerticalSashTop?(sash: Sash): number;
	getVerticalSashHeight?(sash: Sash): number;
}

export interface IHorizontalSashLayoutProvider extends ISashLayoutProvider {
	getHorizontalSashTop(sash: Sash): number;
	getHorizontalSashLeft?(sash: Sash): number;
	getHorizontalSashWidth?(sash: Sash): number;
}

export interface ISashEvent {
	startX: number;
	currentX: number;
	startY: number;
	currentY: number;
}

export interface ISashOptions {
	baseSize?: number;
	orientation?: Orientation;
}

export enum Orientation {
	VERTICAL,
	HORIZONTAL
}

B
Benjamin Pasero 已提交
50
export class Sash extends EventEmitter {
E
Erich Gamma 已提交
51

B
Benjamin Pasero 已提交
52 53
	private $e: Builder;
	private gesture: Gesture;
E
Erich Gamma 已提交
54 55 56 57 58 59 60 61 62 63 64
	private layoutProvider: ISashLayoutProvider;
	private isDisabled: boolean;
	private hidden: boolean;
	private orientation: Orientation;
	private size: number;

	constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions = {}) {
		super();

		this.$e = $('.monaco-sash').appendTo(container);

B
Benjamin Pasero 已提交
65 66 67 68
		if (isMacintosh) {
			this.$e.addClass('mac');
		}

B
Benjamin Pasero 已提交
69
		this.gesture = new Gesture(this.$e.getHTMLElement());
E
Erich Gamma 已提交
70

M
Maxime Quandalle 已提交
71 72
		this.$e.on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { this.onMouseDown(e); });
		this.$e.on(DOM.EventType.DBLCLICK, (e: MouseEvent) => { this.emit('reset', e); });
B
Benjamin Pasero 已提交
73
		this.$e.on(EventType.Start, (e: GestureEvent) => { this.onTouchStart(e); });
E
Erich Gamma 已提交
74 75

		this.orientation = options.orientation || Orientation.VERTICAL;
M
Maxime Quandalle 已提交
76
		this.$e.addClass(this.getOrientation());
E
Erich Gamma 已提交
77 78 79

		this.size = options.baseSize || 5;

B
Benjamin Pasero 已提交
80
		if (isIPad) {
E
Erich Gamma 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
			this.size *= 4; // see also http://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications
			this.$e.addClass('touch');
		}

		if (this.orientation === Orientation.HORIZONTAL) {
			this.$e.size(null, this.size);
		} else {
			this.$e.size(this.size);
		}

		this.isDisabled = false;
		this.hidden = false;
		this.layoutProvider = layoutProvider;
	}

	public getHTMLElement(): HTMLElement {
		return this.$e.getHTMLElement();
	}

M
Maxime Quandalle 已提交
100 101 102 103
	private getOrientation(): 'horizontal' | 'vertical' {
		return this.orientation === Orientation.HORIZONTAL ? 'horizontal' : 'vertical';
	}

E
Erich Gamma 已提交
104 105 106 107 108 109 110
	private onMouseDown(e: MouseEvent): void {
		DOM.EventHelper.stop(e, false);

		if (this.isDisabled) {
			return;
		}

B
Benjamin Pasero 已提交
111 112 113
		let mouseDownEvent = new StandardMouseEvent(e);
		let startX = mouseDownEvent.posx;
		let startY = mouseDownEvent.posy;
E
Erich Gamma 已提交
114

B
Benjamin Pasero 已提交
115
		let startEvent: ISashEvent = {
E
Erich Gamma 已提交
116 117 118
			startX: startX,
			currentX: startX,
			startY: startY,
B
Benjamin Pasero 已提交
119
			currentY: startY
E
Erich Gamma 已提交
120 121 122 123 124
		};

		this.$e.addClass('active');
		this.emit('start', startEvent);

B
Benjamin Pasero 已提交
125
		let $window = $(window);
B
Benjamin Pasero 已提交
126
		let containerCssClass = `${this.getOrientation()}-cursor-container${isMacintosh ? '-mac' : ''}`;
E
Erich Gamma 已提交
127

B
Benjamin Pasero 已提交
128 129
		let lastCurrentX = startX;
		let lastCurrentY = startY;
E
Erich Gamma 已提交
130 131 132

		$window.on('mousemove', (e: MouseEvent) => {
			DOM.EventHelper.stop(e, false);
B
Benjamin Pasero 已提交
133
			let mouseMoveEvent = new StandardMouseEvent(e);
E
Erich Gamma 已提交
134

B
Benjamin Pasero 已提交
135
			let event: ISashEvent = {
E
Erich Gamma 已提交
136 137 138
				startX: startX,
				currentX: mouseMoveEvent.posx,
				startY: startY,
B
Benjamin Pasero 已提交
139
				currentY: mouseMoveEvent.posy
E
Erich Gamma 已提交
140 141 142 143 144 145 146 147 148 149 150 151
			};

			lastCurrentX = mouseMoveEvent.posx;
			lastCurrentY = mouseMoveEvent.posy;

			this.emit('change', event);
		}).once('mouseup', (e: MouseEvent) => {
			DOM.EventHelper.stop(e, false);
			this.$e.removeClass('active');
			this.emit('end');

			$window.off('mousemove');
M
Maxime Quandalle 已提交
152
			document.body.classList.remove(containerCssClass);
E
Erich Gamma 已提交
153 154
		});

M
Maxime Quandalle 已提交
155
		document.body.classList.add(containerCssClass);
E
Erich Gamma 已提交
156 157
	}

B
Benjamin Pasero 已提交
158
	private onTouchStart(event: GestureEvent): void {
E
Erich Gamma 已提交
159 160
		DOM.EventHelper.stop(event);

B
Benjamin Pasero 已提交
161
		let listeners: IDisposable[] = [];
E
Erich Gamma 已提交
162

B
Benjamin Pasero 已提交
163 164
		let startX = event.pageX;
		let startY = event.pageY;
E
Erich Gamma 已提交
165 166 167 168 169

		this.emit('start', {
			startX: startX,
			currentX: startX,
			startY: startY,
B
Benjamin Pasero 已提交
170
			currentY: startY
E
Erich Gamma 已提交
171 172
		});

B
Benjamin Pasero 已提交
173 174
		let lastCurrentX = startX;
		let lastCurrentY = startY;
E
Erich Gamma 已提交
175

B
Benjamin Pasero 已提交
176 177
		listeners.push(DOM.addDisposableListener(this.$e.getHTMLElement(), EventType.Change, (event: GestureEvent) => {
			if (types.isNumber(event.pageX) && types.isNumber(event.pageY)) {
E
Erich Gamma 已提交
178 179 180 181
				this.emit('change', {
					startX: startX,
					currentX: event.pageX,
					startY: startY,
B
Benjamin Pasero 已提交
182
					currentY: event.pageY
E
Erich Gamma 已提交
183 184 185 186 187 188 189
				});

				lastCurrentX = event.pageX;
				lastCurrentY = event.pageY;
			}
		}));

B
Benjamin Pasero 已提交
190
		listeners.push(DOM.addDisposableListener(this.$e.getHTMLElement(), EventType.End, (event: GestureEvent) => {
E
Erich Gamma 已提交
191
			this.emit('end');
J
Joao Moreno 已提交
192
			dispose(listeners);
E
Erich Gamma 已提交
193 194 195 196
		}));
	}

	public layout(): void {
B
Benjamin Pasero 已提交
197
		let style: { top?: string; left?: string; height?: string; width?: string; };
E
Erich Gamma 已提交
198 199

		if (this.orientation === Orientation.VERTICAL) {
B
Benjamin Pasero 已提交
200
			let verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
E
Erich Gamma 已提交
201 202 203 204 205 206 207 208 209 210
			style = { left: verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px' };

			if (verticalProvider.getVerticalSashTop) {
				style.top = verticalProvider.getVerticalSashTop(this) + 'px';
			}

			if (verticalProvider.getVerticalSashHeight) {
				style.height = verticalProvider.getVerticalSashHeight(this) + 'px';
			}
		} else {
B
Benjamin Pasero 已提交
211
			let horizontalProvider = (<IHorizontalSashLayoutProvider>this.layoutProvider);
E
Erich Gamma 已提交
212 213 214
			style = { top: horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px' };

			if (horizontalProvider.getHorizontalSashLeft) {
J
Joao Moreno 已提交
215
				style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px';
E
Erich Gamma 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
			}

			if (horizontalProvider.getHorizontalSashWidth) {
				style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px';
			}
		}

		this.$e.style(style);
	}

	public show(): void {
		this.hidden = false;
		this.$e.show();
	}

	public hide(): void {
		this.hidden = true;
		this.$e.hide();
	}

	public isHidden(): boolean {
		return this.hidden;
	}

	public enable(): void {
		this.$e.removeClass('disabled');
		this.isDisabled = false;
	}

	public disable(): void {
		this.$e.addClass('disabled');
		this.isDisabled = true;
	}

	public dispose(): void {
		if (this.$e) {
			this.$e.destroy();
			this.$e = null;
		}

		super.dispose();
	}
}