/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/part'; import { Component } from 'vs/workbench/common/component'; import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService'; import { Dimension, size, IDimension } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { assertIsDefined } from 'vs/base/common/types'; export interface IPartOptions { hasTitle?: boolean; borderWidth?: () => number; } export interface ILayoutContentResult { titleSize: IDimension; contentSize: IDimension; } /** * Parts are layed out in the workbench and have their own layout that * arranges an optional title and mandatory content area to show content. */ export abstract class Part extends Component implements ISerializableView { private _dimension: Dimension | undefined; get dimension(): Dimension | undefined { return this._dimension; } protected _onDidVisibilityChange = this._register(new Emitter()); readonly onDidVisibilityChange = this._onDidVisibilityChange.event; private parent: HTMLElement | undefined; private titleArea: HTMLElement | undefined; private contentArea: HTMLElement | undefined; private partLayout: PartLayout | undefined; constructor( id: string, private options: IPartOptions, themeService: IThemeService, storageService: IStorageService, protected readonly layoutService: IWorkbenchLayoutService ) { super(id, themeService, storageService); layoutService.registerPart(this); } protected onThemeChange(theme: IColorTheme): void { // only call if our create() method has been called if (this.parent) { super.onThemeChange(theme); } } updateStyles(): void { super.updateStyles(); } /** * Note: Clients should not call this method, the workbench calls this * method. Calling it otherwise may result in unexpected behavior. * * Called to create title and content area of the part. */ create(parent: HTMLElement, options?: object): void { this.parent = parent; this.titleArea = this.createTitleArea(parent, options); this.contentArea = this.createContentArea(parent, options); this.partLayout = new PartLayout(this.options, this.contentArea); this.updateStyles(); } /** * Returns the overall part container. */ getContainer(): HTMLElement | undefined { return this.parent; } /** * Subclasses override to provide a title area implementation. */ protected createTitleArea(parent: HTMLElement, options?: object): HTMLElement | undefined { return undefined; } /** * Returns the title area container. */ protected getTitleArea(): HTMLElement | undefined { return this.titleArea; } /** * Subclasses override to provide a content area implementation. */ protected createContentArea(parent: HTMLElement, options?: object): HTMLElement | undefined { return undefined; } /** * Returns the content area container. */ protected getContentArea(): HTMLElement | undefined { return this.contentArea; } /** * Layout title and content area in the given dimension. */ protected layoutContents(width: number, height: number): ILayoutContentResult { const partLayout = assertIsDefined(this.partLayout); return partLayout.layout(width, height); } //#region ISerializableView private _onDidChange = this._register(new Emitter()); get onDidChange(): Event { return this._onDidChange.event; } element!: HTMLElement; abstract minimumWidth: number; abstract maximumWidth: number; abstract minimumHeight: number; abstract maximumHeight: number; layout(width: number, height: number): void { this._dimension = new Dimension(width, height); } setVisible(visible: boolean) { this._onDidVisibilityChange.fire(visible); } abstract toJSON(): object; //#endregion } class PartLayout { private static readonly TITLE_HEIGHT = 35; constructor(private options: IPartOptions, private contentArea: HTMLElement | undefined) { } layout(width: number, height: number): ILayoutContentResult { // Title Size: Width (Fill), Height (Variable) let titleSize: Dimension; if (this.options && this.options.hasTitle) { titleSize = new Dimension(width, Math.min(height, PartLayout.TITLE_HEIGHT)); } else { titleSize = new Dimension(0, 0); } let contentWidth = width; if (this.options && typeof this.options.borderWidth === 'function') { contentWidth -= this.options.borderWidth(); // adjust for border size } // Content Size: Width (Fill), Height (Variable) const contentSize = new Dimension(contentWidth, height - titleSize.height); // Content if (this.contentArea) { size(this.contentArea, contentSize.width, contentSize.height); } return { titleSize, contentSize }; } }