layout.ts 21.6 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';

J
Johannes Rieken 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19
import { Dimension, Builder, Box } from 'vs/base/browser/builder';
import { Part } from 'vs/workbench/browser/part';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
import { Sash, ISashEvent, IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider, Orientation } from 'vs/base/browser/ui/sash/sash';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IPartService, Position } from 'vs/workbench/services/part/common/partService';
import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IEventService } from 'vs/platform/event/common/event';
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
20
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
E
Erich Gamma 已提交
21

22
const DEFAULT_MIN_SIDEBAR_PART_WIDTH = 170;
I
isidor 已提交
23
const DEFAULT_MIN_PANEL_PART_HEIGHT = 77;
24 25
const DEFAULT_MIN_EDITOR_PART_HEIGHT = 70;
const DEFAULT_MIN_EDITOR_PART_WIDTH = 220;
I
isidor 已提交
26
const DEFAULT_PANEL_HEIGHT_COEFFICIENT = 0.4;
E
Erich Gamma 已提交
27
const HIDE_SIDEBAR_WIDTH_THRESHOLD = 50;
I
isidor 已提交
28
const HIDE_PANEL_HEIGHT_THRESHOLD = 50;
E
Erich Gamma 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

export class LayoutOptions {
	public margin: Box;

	constructor() {
		this.margin = new Box(0, 0, 0, 0);
	}

	public setMargin(margin: Box): LayoutOptions {
		this.margin = margin;

		return this;
	}
}

interface ComputedStyles {
	activitybar: { minWidth: number; };
	sidebar: { minWidth: number; };
B
Benjamin Pasero 已提交
47
	panel: { minHeight: number; };
48
	editor: { minWidth: number; minHeight: number; };
E
Erich Gamma 已提交
49 50 51
	statusbar: { height: number; };
}

B
Benjamin Pasero 已提交
52 53 54 55 56
export interface ILayoutOptions {
	forceStyleReCompute?: boolean;
	toggleMaximizedPanel?: boolean;
}

E
Erich Gamma 已提交
57
/**
B
Benjamin Pasero 已提交
58
 * The workbench layout is responsible to lay out all parts that make the Workbench.
E
Erich Gamma 已提交
59
 */
I
isidor 已提交
60
export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider {
E
Erich Gamma 已提交
61

I
isidor 已提交
62
	private static sashXWidthSettingsKey = 'workbench.sidebar.width';
I
isidor 已提交
63
	private static sashYHeightSettingsKey = 'workbench.panel.height';
E
Erich Gamma 已提交
64 65 66 67 68 69

	private parent: Builder;
	private workbenchContainer: Builder;
	private activitybar: Part;
	private editor: Part;
	private sidebar: Part;
B
Benjamin Pasero 已提交
70
	private panel: Part;
E
Erich Gamma 已提交
71 72 73
	private statusbar: Part;
	private quickopen: QuickOpenController;
	private options: LayoutOptions;
M
Martin Aeschlimann 已提交
74
	private toUnbind: IDisposable[];
E
Erich Gamma 已提交
75 76
	private computedStyles: ComputedStyles;
	private workbenchSize: Dimension;
I
isidor 已提交
77 78
	private sashX: Sash;
	private sashY: Sash;
E
Erich Gamma 已提交
79 80
	private startSidebarWidth: number;
	private sidebarWidth: number;
I
isidor 已提交
81
	private sidebarHeight: number;
I
isidor 已提交
82 83
	private startPanelHeight: number;
	private panelHeight: number;
84
	private panelHeightBeforeMaximized: number;
I
isidor 已提交
85
	private panelWidth: number;
86
	private layoutEditorGroupsVertically: boolean;
E
Erich Gamma 已提交
87

I
isidor 已提交
88
	// Take parts as an object bag since instatation service does not have typings for constructors with 9+ arguments
E
Erich Gamma 已提交
89 90 91
	constructor(
		parent: Builder,
		workbenchContainer: Builder,
I
isidor 已提交
92 93 94 95 96 97 98
		parts: {
			activitybar: Part,
			editor: Part,
			sidebar: Part,
			panel: Part,
			statusbar: Part
		},
E
Erich Gamma 已提交
99 100 101
		quickopen: QuickOpenController,
		options: LayoutOptions,
		@IStorageService private storageService: IStorageService,
M
Martin Aeschlimann 已提交
102
		@IEventService eventService: IEventService,
E
Erich Gamma 已提交
103 104
		@IContextViewService private contextViewService: IContextViewService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
105
		@IEditorGroupService private editorGroupService: IEditorGroupService,
M
Martin Aeschlimann 已提交
106
		@IPartService private partService: IPartService,
107
		@IConfigurationService configurationService: IConfigurationService,
M
Maxime Quandalle 已提交
108
		@IViewletService private viewletService: IViewletService,
M
Martin Aeschlimann 已提交
109
		@IThemeService themeService: IThemeService
E
Erich Gamma 已提交
110 111 112
	) {
		this.parent = parent;
		this.workbenchContainer = workbenchContainer;
I
isidor 已提交
113 114 115
		this.activitybar = parts.activitybar;
		this.editor = parts.editor;
		this.sidebar = parts.sidebar;
B
Benjamin Pasero 已提交
116
		this.panel = parts.panel;
I
isidor 已提交
117
		this.statusbar = parts.statusbar;
E
Erich Gamma 已提交
118 119 120 121
		this.quickopen = quickopen;
		this.options = options || new LayoutOptions();
		this.toUnbind = [];
		this.computedStyles = null;
122

I
isidor 已提交
123
		this.sashX = new Sash(this.workbenchContainer.getHTMLElement(), this, {
E
Erich Gamma 已提交
124 125
			baseSize: 5
		});
126

I
isidor 已提交
127
		this.sashY = new Sash(this.workbenchContainer.getHTMLElement(), this, {
I
isidor 已提交
128
			baseSize: 4,
I
isidor 已提交
129 130
			orientation: Orientation.HORIZONTAL
		});
E
Erich Gamma 已提交
131

I
isidor 已提交
132
		this.sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXWidthSettingsKey, StorageScope.GLOBAL, -1);
I
isidor 已提交
133
		this.panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0);
E
Erich Gamma 已提交
134

135
		this.layoutEditorGroupsVertically = (this.editorGroupService.getGroupOrientation() !== 'horizontal');
136

M
Martin Aeschlimann 已提交
137
		this.toUnbind.push(themeService.onDidColorThemeChange(_ => this.relayout()));
138
		this.toUnbind.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged()));
139
		this.toUnbind.push(editorGroupService.onGroupOrientationChanged(e => this.onGroupOrientationChanged()));
M
Martin Aeschlimann 已提交
140

E
Erich Gamma 已提交
141 142 143 144 145
		this.registerSashListeners();
	}

	private registerSashListeners(): void {
		let startX: number = 0;
I
isidor 已提交
146
		let startY: number = 0;
E
Erich Gamma 已提交
147

A
Alex Dima 已提交
148
		this.sashX.addListener2('start', (e: ISashEvent) => {
E
Erich Gamma 已提交
149 150 151 152
			this.startSidebarWidth = this.sidebarWidth;
			startX = e.startX;
		});

A
Alex Dima 已提交
153
		this.sashY.addListener2('start', (e: ISashEvent) => {
I
isidor 已提交
154
			this.startPanelHeight = this.panelHeight;
I
isidor 已提交
155 156 157
			startY = e.startY;
		});

A
Alex Dima 已提交
158
		this.sashX.addListener2('change', (e: ISashEvent) => {
E
Erich Gamma 已提交
159 160 161 162 163 164 165 166 167 168
			let doLayout = false;
			let sidebarPosition = this.partService.getSideBarPosition();
			let isSidebarHidden = this.partService.isSideBarHidden();
			let newSashWidth = (sidebarPosition === Position.LEFT) ? this.startSidebarWidth + e.currentX - startX : this.startSidebarWidth - e.currentX + startX;

			// Sidebar visible
			if (!isSidebarHidden) {

				// Automatically hide side bar when a certain threshold is met
				if (newSashWidth + HIDE_SIDEBAR_WIDTH_THRESHOLD < this.computedStyles.sidebar.minWidth) {
169
					let dragCompensation = DEFAULT_MIN_SIDEBAR_PART_WIDTH - HIDE_SIDEBAR_WIDTH_THRESHOLD;
E
Erich Gamma 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
					this.partService.setSideBarHidden(true);
					startX = (sidebarPosition === Position.LEFT) ? Math.max(this.computedStyles.activitybar.minWidth, e.currentX - dragCompensation) : Math.min(e.currentX + dragCompensation, this.workbenchSize.width - this.computedStyles.activitybar.minWidth);
					this.sidebarWidth = this.startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from
				}

				// Otherwise size the sidebar accordingly
				else {
					this.sidebarWidth = Math.max(this.computedStyles.sidebar.minWidth, newSashWidth); // Sidebar can not become smaller than MIN_PART_WIDTH
					doLayout = newSashWidth >= this.computedStyles.sidebar.minWidth;
				}
			}

			// Sidebar hidden
			else {
				if ((sidebarPosition === Position.LEFT && e.currentX - startX >= this.computedStyles.sidebar.minWidth) ||
					(sidebarPosition === Position.RIGHT && startX - e.currentX >= this.computedStyles.sidebar.minWidth)) {
					this.startSidebarWidth = this.computedStyles.sidebar.minWidth - (sidebarPosition === Position.LEFT ? e.currentX - startX : startX - e.currentX);
					this.sidebarWidth = this.computedStyles.sidebar.minWidth;
					this.partService.setSideBarHidden(false);
				}
			}

			if (doLayout) {
				this.layout();
			}
		});

A
Alex Dima 已提交
197
		this.sashY.addListener2('change', (e: ISashEvent) => {
I
isidor 已提交
198
			let doLayout = false;
I
isidor 已提交
199
			let isPanelHidden = this.partService.isPanelHidden();
200
			let isStatusbarHidden = this.partService.isStatusBarHidden();
I
isidor 已提交
201
			let newSashHeight = this.startPanelHeight - (e.currentY - startY);
I
isidor 已提交
202 203

			// Panel visible
I
isidor 已提交
204
			if (!isPanelHidden) {
205 206 207 208
				// Automatically hide panel when a certain threshold is met
				if (newSashHeight + HIDE_PANEL_HEIGHT_THRESHOLD < this.computedStyles.panel.minHeight) {
					let dragCompensation = DEFAULT_MIN_PANEL_PART_HEIGHT - HIDE_PANEL_HEIGHT_THRESHOLD;
					this.partService.setPanelHidden(true);
209 210
					let statusbarHeight = isStatusbarHidden ? 0 : this.computedStyles.statusbar.height;
					startY = Math.min(this.sidebarHeight - statusbarHeight, e.currentY + dragCompensation);
M
Maxime Quandalle 已提交
211
					this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel height we started from
212 213 214 215 216 217 218 219
				}

				// Otherwise size the panel accordingly
				else {
					this.panelHeight = Math.max(this.computedStyles.panel.minHeight, newSashHeight); // Panel can not become smaller than MIN_PART_HEIGHT
					doLayout = newSashHeight >= this.computedStyles.panel.minHeight;
				}
			}
I
isidor 已提交
220

221 222 223 224 225 226 227
			// Panel hidden
			else {
				if (startY - e.currentY >= this.computedStyles.panel.minHeight) {
					this.startPanelHeight = 0;
					this.panelHeight = this.computedStyles.panel.minHeight;
					this.partService.setPanelHidden(false);
				}
I
isidor 已提交
228
			}
229

I
isidor 已提交
230 231 232 233 234
			if (doLayout) {
				this.layout();
			}
		});

A
Alex Dima 已提交
235
		this.sashX.addListener2('end', () => {
I
isidor 已提交
236 237
			this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL);
		});
M
Maxime Quandalle 已提交
238

A
Alex Dima 已提交
239
		this.sashY.addListener2('end', () => {
I
isidor 已提交
240
			this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL);
E
Erich Gamma 已提交
241
		});
M
Maxime Quandalle 已提交
242

A
Alex Dima 已提交
243
		this.sashY.addListener2('reset', () => {
I
isidor 已提交
244
			this.panelHeight = this.sidebarHeight * DEFAULT_PANEL_HEIGHT_COEFFICIENT;
M
Maxime Quandalle 已提交
245 246 247 248 249
			this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL);
			this.partService.setPanelHidden(false);
			this.layout();
		});

A
Alex Dima 已提交
250
		this.sashX.addListener2('reset', () => {
M
Maxime Quandalle 已提交
251 252
			let activeViewlet = this.viewletService.getActiveViewlet();
			let optimalWidth = activeViewlet && activeViewlet.getOptimalWidth();
253
			this.sidebarWidth = Math.max(DEFAULT_MIN_SIDEBAR_PART_WIDTH, optimalWidth || 0);
M
Maxime Quandalle 已提交
254 255 256 257
			this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL);
			this.partService.setSideBarHidden(false);
			this.layout();
		});
E
Erich Gamma 已提交
258 259
	}

260
	private onEditorsChanged(): void {
E
Erich Gamma 已提交
261

262
		// Make sure that we layout properly in case we detect that the sidebar or panel is large enought to cause
E
Erich Gamma 已提交
263 264
		// multiple opened editors to go below minimal size. The fix is to trigger a layout for any editor
		// input change that falls into this category.
265
		if (this.workbenchSize && (this.sidebarWidth || this.panelHeight)) {
E
Erich Gamma 已提交
266
			let visibleEditors = this.editorService.getVisibleEditors().length;
267
			if (visibleEditors > 1) {
268 269
				const sidebarOverflow = this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < visibleEditors * DEFAULT_MIN_EDITOR_PART_WIDTH);
				const panelOverflow = !this.layoutEditorGroupsVertically && (this.workbenchSize.height - this.panelHeight < visibleEditors * DEFAULT_MIN_EDITOR_PART_HEIGHT);
270 271 272 273

				if (sidebarOverflow || panelOverflow) {
					this.layout();
				}
E
Erich Gamma 已提交
274 275 276 277
			}
		}
	}

278 279
	private onGroupOrientationChanged(): void {
		const newLayoutEditorGroupsVertically = (this.editorGroupService.getGroupOrientation() !== 'horizontal');
280

281 282
		const doLayout = this.layoutEditorGroupsVertically !== newLayoutEditorGroupsVertically;
		this.layoutEditorGroupsVertically = newLayoutEditorGroupsVertically;
283 284 285 286 287 288

		if (doLayout) {
			this.layout();
		}
	}

M
Martin Aeschlimann 已提交
289
	private relayout(): void {
E
Erich Gamma 已提交
290

M
Martin Aeschlimann 已提交
291 292 293 294 295
		// Recompute Styles
		this.computeStyle();
		this.editor.getLayout().computeStyle();
		this.sidebar.getLayout().computeStyle();
		this.panel.getLayout().computeStyle();
E
Erich Gamma 已提交
296

M
Martin Aeschlimann 已提交
297 298
		// Trigger Layout
		this.layout();
E
Erich Gamma 已提交
299 300 301
	}

	private computeStyle(): void {
I
isidor 已提交
302
		const sidebarStyle = this.sidebar.getContainer().getComputedStyle();
B
Benjamin Pasero 已提交
303
		const panelStyle = this.panel.getContainer().getComputedStyle();
I
isidor 已提交
304 305
		const editorStyle = this.editor.getContainer().getComputedStyle();
		const activitybarStyle = this.activitybar.getContainer().getComputedStyle();
B
Benjamin Pasero 已提交
306
		const statusbarStyle = this.statusbar.getContainer().getComputedStyle();
E
Erich Gamma 已提交
307 308 309 310 311 312 313

		this.computedStyles = {
			activitybar: {
				minWidth: parseInt(activitybarStyle.getPropertyValue('min-width'), 10) || 0
			},

			sidebar: {
314
				minWidth: parseInt(sidebarStyle.getPropertyValue('min-width'), 10) || DEFAULT_MIN_SIDEBAR_PART_WIDTH
E
Erich Gamma 已提交
315 316
			},

I
isidor 已提交
317
			panel: {
B
Benjamin Pasero 已提交
318
				minHeight: parseInt(panelStyle.getPropertyValue('min-height'), 10) || DEFAULT_MIN_PANEL_PART_HEIGHT
I
isidor 已提交
319 320
			},

E
Erich Gamma 已提交
321
			editor: {
322 323
				minWidth: parseInt(editorStyle.getPropertyValue('min-width'), 10) || DEFAULT_MIN_EDITOR_PART_WIDTH,
				minHeight: DEFAULT_MIN_EDITOR_PART_HEIGHT
E
Erich Gamma 已提交
324 325 326
			},

			statusbar: {
B
Benjamin Pasero 已提交
327
				height: parseInt(statusbarStyle.getPropertyValue('height'), 10) || 18
E
Erich Gamma 已提交
328 329 330 331
			}
		};
	}

B
Benjamin Pasero 已提交
332 333
	public layout(options?: ILayoutOptions): void {
		if (options && options.forceStyleReCompute) {
E
Erich Gamma 已提交
334 335 336
			this.computeStyle();
			this.editor.getLayout().computeStyle();
			this.sidebar.getLayout().computeStyle();
B
Benjamin Pasero 已提交
337
			this.panel.getLayout().computeStyle();
E
Erich Gamma 已提交
338 339 340 341 342 343 344 345
		}

		if (!this.computedStyles) {
			this.computeStyle();
		}

		this.workbenchSize = this.getWorkbenchArea();

S
Sanders Lauture 已提交
346
		const isActivityBarHidden = this.partService.isActivityBarHidden();
I
isidor 已提交
347
		const isSidebarHidden = this.partService.isSideBarHidden();
I
isidor 已提交
348
		const isPanelHidden = this.partService.isPanelHidden();
I
isidor 已提交
349
		const sidebarPosition = this.partService.getSideBarPosition();
350
		const isStatusbarHidden = this.partService.isStatusBarHidden();
E
Erich Gamma 已提交
351 352 353 354 355 356 357 358 359 360 361

		// Sidebar
		let sidebarWidth: number;
		if (isSidebarHidden) {
			sidebarWidth = 0;
		} else if (this.sidebarWidth !== -1) {
			sidebarWidth = Math.max(this.computedStyles.sidebar.minWidth, this.sidebarWidth);
		} else {
			sidebarWidth = this.workbenchSize.width / 5;
			this.sidebarWidth = sidebarWidth;
		}
B
Benjamin Pasero 已提交
362

363
		let statusbarHeight = isStatusbarHidden ? 0 : this.computedStyles.statusbar.height;
E
Erich Gamma 已提交
364

365
		this.sidebarHeight = this.workbenchSize.height - statusbarHeight;
I
isidor 已提交
366
		let sidebarSize = new Dimension(sidebarWidth, this.sidebarHeight);
E
Erich Gamma 已提交
367 368 369

		// Activity Bar
		let activityBarMinWidth = this.computedStyles.activitybar.minWidth;
S
Sanders Lauture 已提交
370 371 372 373 374 375 376
		let activityBarWidth: number;
		if (isActivityBarHidden) {
			activityBarWidth = 0;
		} else {
			activityBarWidth = activityBarMinWidth;
		}
		let activityBarSize = new Dimension(activityBarWidth, sidebarSize.height);
E
Erich Gamma 已提交
377

I
isidor 已提交
378 379
		// Panel part
		let panelHeight: number;
I
isidor 已提交
380
		const maxPanelHeight = sidebarSize.height - DEFAULT_MIN_EDITOR_PART_HEIGHT;
I
isidor 已提交
381
		if (isPanelHidden) {
I
isidor 已提交
382
			panelHeight = 0;
I
isidor 已提交
383
		} else if (this.panelHeight > 0) {
I
isidor 已提交
384
			panelHeight = Math.min(maxPanelHeight, Math.max(this.computedStyles.panel.minHeight, this.panelHeight));
I
isidor 已提交
385
		} else {
I
isidor 已提交
386
			panelHeight = sidebarSize.height * DEFAULT_PANEL_HEIGHT_COEFFICIENT;
I
isidor 已提交
387
		}
B
Benjamin Pasero 已提交
388
		if (options && options.toggleMaximizedPanel) {
389 390 391
			const heightToSwap = panelHeight;
			panelHeight = panelHeight === maxPanelHeight ? Math.max(this.computedStyles.panel.minHeight, Math.min(this.panelHeightBeforeMaximized, maxPanelHeight)) : maxPanelHeight;
			this.panelHeightBeforeMaximized = heightToSwap;
I
isidor 已提交
392
		}
I
isidor 已提交
393
		const panelDimension = new Dimension(this.workbenchSize.width - sidebarSize.width - activityBarSize.width, panelHeight);
I
isidor 已提交
394
		this.panelWidth = panelDimension.width;
I
isidor 已提交
395

E
Erich Gamma 已提交
396 397 398 399 400 401 402 403
		// Editor
		let editorSize = {
			width: 0,
			height: 0,
			remainderLeft: 0,
			remainderRight: 0
		};

404 405
		editorSize.width = panelDimension.width;
		editorSize.height = sidebarSize.height - panelDimension.height;
E
Erich Gamma 已提交
406 407 408

		// Sidebar hidden
		if (isSidebarHidden) {
S
Sanders Lauture 已提交
409
			editorSize.width = this.workbenchSize.width - activityBarSize.width;
E
Erich Gamma 已提交
410 411 412 413 414 415 416 417 418 419 420 421

			if (sidebarPosition === Position.LEFT) {
				editorSize.remainderLeft = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2);
				editorSize.remainderRight = this.workbenchSize.width - editorSize.width - editorSize.remainderLeft;
			} else {
				editorSize.remainderRight = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2);
				editorSize.remainderLeft = this.workbenchSize.width - editorSize.width - editorSize.remainderRight;
			}
		}

		// Assert Sidebar and Editor Size to not overflow
		let editorMinWidth = this.computedStyles.editor.minWidth;
422
		let editorMinHeight = this.computedStyles.editor.minHeight;
E
Erich Gamma 已提交
423 424
		let visibleEditorCount = this.editorService.getVisibleEditors().length;
		if (visibleEditorCount > 1) {
425
			if (this.layoutEditorGroupsVertically) {
426 427 428 429
				editorMinWidth *= visibleEditorCount; // when editors layout vertically, multiply the min editor width by number of visible editors
			} else {
				editorMinHeight *= visibleEditorCount; // when editors layout horizontally, multiply the min editor height by number of visible editors
			}
E
Erich Gamma 已提交
430
		}
B
Benjamin Pasero 已提交
431

E
Erich Gamma 已提交
432 433 434
		if (editorSize.width < editorMinWidth) {
			let diff = editorMinWidth - editorSize.width;
			editorSize.width = editorMinWidth;
435
			panelDimension.width = editorMinWidth;
E
Erich Gamma 已提交
436
			sidebarSize.width -= diff;
437 438 439 440 441 442 443 444
			sidebarSize.width = Math.max(DEFAULT_MIN_SIDEBAR_PART_WIDTH, sidebarSize.width);
		}

		if (editorSize.height < editorMinHeight) {
			let diff = editorMinHeight - editorSize.height;
			editorSize.height = editorMinHeight;
			panelDimension.height -= diff;
			panelDimension.height = Math.max(DEFAULT_MIN_PANEL_PART_HEIGHT, panelDimension.height);
E
Erich Gamma 已提交
445 446 447 448
		}

		if (!isSidebarHidden) {
			this.sidebarWidth = sidebarSize.width;
I
isidor 已提交
449
			this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL);
E
Erich Gamma 已提交
450 451
		}

I
isidor 已提交
452 453 454
		if (!isPanelHidden) {
			this.panelHeight = panelDimension.height;
			this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL);
I
isidor 已提交
455 456
		}

E
Erich Gamma 已提交
457 458 459 460 461
		// Workbench
		this.workbenchContainer
			.position(this.options.margin.top, this.options.margin.right, this.options.margin.bottom, this.options.margin.left, 'relative')
			.size(this.workbenchSize.width, this.workbenchSize.height);

B
Benjamin Pasero 已提交
462 463 464 465 466 467 468
		// Bug on Chrome: Sometimes Chrome wants to scroll the workbench container on layout changes. The fix is to reset scrolling in this case.
		const workbenchContainer = this.workbenchContainer.getHTMLElement();
		if (workbenchContainer.scrollTop > 0) {
			workbenchContainer.scrollTop = 0;
		}
		if (workbenchContainer.scrollLeft > 0) {
			workbenchContainer.scrollLeft = 0;
E
Erich Gamma 已提交
469 470
		}

I
isidor 已提交
471
		// Editor Part and Panel part
E
Erich Gamma 已提交
472
		this.editor.getContainer().size(editorSize.width, editorSize.height);
B
Benjamin Pasero 已提交
473
		this.panel.getContainer().size(panelDimension.width, panelDimension.height);
E
Erich Gamma 已提交
474

475
		const editorBottom = statusbarHeight + panelDimension.height;
E
Erich Gamma 已提交
476
		if (isSidebarHidden) {
477
			this.editor.getContainer().position(0, editorSize.remainderRight, editorBottom, editorSize.remainderLeft);
478
			this.panel.getContainer().position(editorSize.height, editorSize.remainderRight, statusbarHeight, editorSize.remainderLeft);
E
Erich Gamma 已提交
479
		} else if (sidebarPosition === Position.LEFT) {
480
			this.editor.getContainer().position(0, 0, editorBottom, sidebarSize.width + activityBarSize.width);
481
			this.panel.getContainer().position(editorSize.height, 0, statusbarHeight, sidebarSize.width + activityBarSize.width);
E
Erich Gamma 已提交
482
		} else {
483
			this.editor.getContainer().position(0, sidebarSize.width, editorBottom, 0);
484
			this.panel.getContainer().position(editorSize.height, sidebarSize.width, statusbarHeight, 0);
E
Erich Gamma 已提交
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
		}

		// Activity Bar Part
		this.activitybar.getContainer().size(null, activityBarSize.height);
		if (sidebarPosition === Position.LEFT) {
			this.activitybar.getContainer().getHTMLElement().style.right = '';
			this.activitybar.getContainer().position(0, null, 0, 0);
		} else {
			this.activitybar.getContainer().getHTMLElement().style.left = '';
			this.activitybar.getContainer().position(0, 0, 0, null);
		}

		// Sidebar Part
		this.sidebar.getContainer().size(sidebarSize.width, sidebarSize.height);

		if (sidebarPosition === Position.LEFT) {
			this.sidebar.getContainer().position(0, editorSize.width, 0, activityBarSize.width);
		} else {
			this.sidebar.getContainer().position(0, null, 0, editorSize.width);
		}

		// Statusbar Part
B
Benjamin Pasero 已提交
507
		this.statusbar.getContainer().position(this.workbenchSize.height - statusbarHeight);
E
Erich Gamma 已提交
508 509 510 511

		// Quick open
		this.quickopen.layout(this.workbenchSize);

I
isidor 已提交
512 513 514
		// Sashes
		this.sashX.layout();
		this.sashY.layout();
E
Erich Gamma 已提交
515 516 517 518

		// Propagate to Part Layouts
		this.editor.layout(new Dimension(editorSize.width, editorSize.height));
		this.sidebar.layout(sidebarSize);
B
Benjamin Pasero 已提交
519
		this.panel.layout(panelDimension);
E
Erich Gamma 已提交
520 521

		// Propagate to Context View
B
Benjamin Pasero 已提交
522
		this.contextViewService.layout();
E
Erich Gamma 已提交
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	}

	private getWorkbenchArea(): Dimension {

		// Client Area: Parent
		let clientArea = this.parent.getClientArea();

		// Workbench: Client Area - Margins
		return clientArea.substract(this.options.margin);
	}

	public getVerticalSashTop(sash: Sash): number {
		return 0;
	}

	public getVerticalSashLeft(sash: Sash): number {
		let isSidebarHidden = this.partService.isSideBarHidden();
		let sidebarPosition = this.partService.getSideBarPosition();
S
Sanders Lauture 已提交
541 542
		let isActivityBarHidden = this.partService.isActivityBarHidden();
		let activitybarWidth = !isActivityBarHidden ? this.computedStyles.activitybar.minWidth : 0;
E
Erich Gamma 已提交
543 544 545 546 547 548 549 550 551

		if (sidebarPosition === Position.LEFT) {
			return !isSidebarHidden ? this.sidebarWidth + activitybarWidth : activitybarWidth;
		}

		return !isSidebarHidden ? this.workbenchSize.width - this.sidebarWidth - activitybarWidth : this.workbenchSize.width - activitybarWidth;
	}

	public getVerticalSashHeight(sash: Sash): number {
I
isidor 已提交
552
		return this.sidebarHeight;
E
Erich Gamma 已提交
553 554
	}

I
isidor 已提交
555
	public getHorizontalSashTop(sash: Sash): number {
B
Benjamin Pasero 已提交
556
		return 2 + (this.partService.isPanelHidden() ? this.sidebarHeight : this.sidebarHeight - this.panelHeight); // Horizontal sash should be a bit lower than the editor area, thus add 2px #5524
I
isidor 已提交
557 558 559
	}

	public getHorizontalSashLeft(sash: Sash): number {
560
		return this.partService.getSideBarPosition() === Position.LEFT ? this.getVerticalSashLeft(sash) : 0;
I
isidor 已提交
561 562 563
	}

	public getHorizontalSashWidth(sash: Sash): number {
I
isidor 已提交
564
		return this.panelWidth;
I
isidor 已提交
565 566
	}

E
Erich Gamma 已提交
567
	public dispose(): void {
M
Martin Aeschlimann 已提交
568 569 570
		if (this.toUnbind) {
			dispose(this.toUnbind);
			this.toUnbind = null;
E
Erich Gamma 已提交
571 572
		}
	}
B
Benjamin Pasero 已提交
573
}