diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 398a3f5270d4e7c2594e7dc7df8531372a7adfd6..e9b941a942657bf417883ee26628bab3bee2fbc4 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -10,6 +10,7 @@ import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { tail2 as tail } from 'vs/base/common/arrays'; import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles } from './gridview'; +import { Event } from 'vs/base/common/event'; export { Orientation } from './gridview'; @@ -192,9 +193,9 @@ export class Grid implements IDisposable { get minimumWidth(): number { return this.gridview.minimumWidth; } get minimumHeight(): number { return this.gridview.minimumHeight; } - get maximumWidth(): number { return this.gridview.maximumWidth; } get maximumHeight(): number { return this.gridview.maximumHeight; } + get onDidChange(): Event<{ width: number; height: number; }> { return this.gridview.onDidChange; } get element(): HTMLElement { return this.gridview.element; } diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index 7d33647c14dd845a13a756702bbdd661fcaf85c5..9c04e1a08085a9a3298a5b26ecf1f6cb4ef70995 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -104,11 +104,11 @@ class BranchNode implements ISplitView, IDisposable { } get minimumOrthogonalSize(): number { - return this.children.length === 0 ? 0 : this.children.reduce((r, c) => r + c.minimumSize, 0); + return this.splitview.minimumSize; } get maximumOrthogonalSize(): number { - return this.children.length === 0 ? Number.POSITIVE_INFINITY : this.children.reduce((r, c) => r + c.maximumSize, 0); + return this.splitview.maximumSize; } get minimumWidth(): number { @@ -363,7 +363,7 @@ class LeafNode implements ISplitView, IDisposable { } get onDidChange(): Event { - return mapEvent(this.view.onDidChange, this.orientation === Orientation.HORIZONTAL ? ({ width }) => width : ({ height }) => height); + return mapEvent(this.view.onDidChange, this.orientation === Orientation.HORIZONTAL ? e => e && e.width : e => e && e.height); } set orthogonalStartSash(sash: Sash) { @@ -442,6 +442,7 @@ export class GridView implements IDisposable { this._root = root; this.element.appendChild(root.element); this.onDidSashResetRelay.input = root.onDidSashReset; + this._onDidChange.input = mapEvent(root.onDidChange, () => undefined); // TODO } get orientation(): Orientation { @@ -459,29 +460,16 @@ export class GridView implements IDisposable { this.root.orthogonalLayout(orthogonalSize); } - get width(): number { - return this.root.width; - } - - get height(): number { - return this.root.height; - } + get width(): number { return this.root.width; } + get height(): number { return this.root.height; } - get minimumWidth(): number { - return this.root.minimumWidth; - } + get minimumWidth(): number { return this.root.minimumWidth; } + get minimumHeight(): number { return this.root.minimumHeight; } + get maximumWidth(): number { return this.root.maximumHeight; } + get maximumHeight(): number { return this.root.maximumHeight; } - get minimumHeight(): number { - return this.root.minimumHeight; - } - - get maximumWidth(): number { - return this.root.maximumHeight; - } - - get maximumHeight(): number { - return this.root.maximumHeight; - } + private _onDidChange = new Relay<{ width: number; height: number; }>(); + readonly onDidChange = this._onDidChange.event; constructor(options: IGridViewOptions = {}) { this.element = $('.monaco-grid-view'); diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 287af202380d396eb55c5d9e8546498565423f15..4272aa50abf907fa809fec086bf07e62bdccd133 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -148,6 +148,14 @@ export class SplitView implements IDisposable { return this.viewItems.length; } + get minimumSize(): number { + return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0); + } + + get maximumSize(): number { + return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0); + } + private _orthogonalStartSash: Sash | undefined; get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; } set orthogonalStartSash(sash: Sash | undefined) { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index d28eade122655bbb0b2c9727d801f84d67638662..50e5bb3ad7757a8034cc38295ebd25bc7e32a072 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -117,23 +117,23 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr private registerListeners(): void { this._register(this.themeService.onThemeChange(_ => this.layout())); - this._register(this.parts.editor.onDidPreferredSizeChange(() => this.onDidPreferredSizeChange())); + this._register(this.parts.editor.onDidSizeConstraintsChange(() => this.onDidEditorSizeConstraintsChange())); this.registerSashListeners(); } - private onDidPreferredSizeChange(): void { + private onDidEditorSizeConstraintsChange(): void { if (this.workbenchSize && (this.sidebarWidth || this.panelHeight)) { if (this.editorGroupService.count > 1) { - const preferredEditorPartSize = this.parts.editor.preferredSize; + const minimumEditorPartSize = new Dimension(this.parts.editor.minimumWidth, this.parts.editor.minimumHeight); - const sidebarOverflow = this.workbenchSize.width - this.sidebarWidth < preferredEditorPartSize.width; + const sidebarOverflow = this.workbenchSize.width - this.sidebarWidth < minimumEditorPartSize.width; let panelOverflow = false; if (this.partService.getPanelPosition() === Position.RIGHT) { - panelOverflow = this.workbenchSize.width - this.panelWidth - this.sidebarWidth < preferredEditorPartSize.width; + panelOverflow = this.workbenchSize.width - this.panelWidth - this.sidebarWidth < minimumEditorPartSize.width; } else { - panelOverflow = this.workbenchSize.height - this.panelHeight < preferredEditorPartSize.height; + panelOverflow = this.workbenchSize.height - this.panelHeight < minimumEditorPartSize.height; } // Trigger a layout if we detect that either sidebar or panel overflow @@ -191,11 +191,11 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr minSidebarWidth = 0; } - return Math.max(this.partLayoutInfo.panel.minWidth, this.workbenchSize.width - this.parts.editor.preferredSize.width - minSidebarWidth - this.activitybarWidth); + return Math.max(this.partLayoutInfo.panel.minWidth, this.workbenchSize.width - this.parts.editor.minimumWidth - minSidebarWidth - this.activitybarWidth); } private computeMaxPanelHeight(): number { - return Math.max(this.partLayoutInfo.panel.minHeight, this.sidebarHeight /* simplification for: window.height - status.height - title-height */ - this.parts.editor.preferredSize.height); + return Math.max(this.partLayoutInfo.panel.minHeight, this.sidebarHeight /* simplification for: window.height - status.height - title-height */ - this.parts.editor.minimumHeight); } private get sidebarWidth(): number { @@ -208,7 +208,7 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr private set sidebarWidth(value: number) { const panelMinWidth = this.partService.getPanelPosition() === Position.RIGHT && this.partService.isVisible(Parts.PANEL_PART) ? this.partLayoutInfo.panel.minWidth : 0; - const maxSidebarWidth = this.workbenchSize.width - this.activitybarWidth - this.parts.editor.preferredSize.width - panelMinWidth; + const maxSidebarWidth = this.workbenchSize.width - this.activitybarWidth - this.parts.editor.minimumWidth - panelMinWidth; this._sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, Math.min(maxSidebarWidth, value)); } @@ -486,10 +486,10 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr editorSize.width = this.workbenchSize.width - sidebarSize.width - activityBarSize.width - (panelPosition === Position.RIGHT ? panelDimension.width : 0); editorSize.height = sidebarSize.height - (panelPosition === Position.BOTTOM ? panelDimension.height : 0); - // Adjust for Editor Part preferred width - const preferredEditorPartSize = this.parts.editor.preferredSize; - if (editorSize.width < preferredEditorPartSize.width) { - const missingPreferredEditorWidth = preferredEditorPartSize.width - editorSize.width; + // Adjust for Editor Part minimum width + const minimumEditorPartSize = new Dimension(this.parts.editor.minimumWidth, this.parts.editor.minimumHeight); + if (editorSize.width < minimumEditorPartSize.width) { + const missingPreferredEditorWidth = minimumEditorPartSize.width - editorSize.width; let outstandingMissingPreferredEditorWidth = missingPreferredEditorWidth; // Take from Panel if Panel Position on the Right and Visible @@ -512,9 +512,9 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr } } - // Adjust for Editor Part preferred height - if (editorSize.height < preferredEditorPartSize.height) { - const missingPreferredEditorHeight = preferredEditorPartSize.height - editorSize.height; + // Adjust for Editor Part minimum height + if (editorSize.height < minimumEditorPartSize.height) { + const missingPreferredEditorHeight = minimumEditorPartSize.height - editorSize.height; let outstandingMissingPreferredEditorHeight = missingPreferredEditorHeight; // Take from Panel if Panel Position on the Bottom and Visible @@ -713,9 +713,8 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr case Parts.SIDEBAR_PART: this.sidebarWidth = this.sidebarWidth + sizeChangePxWidth; // Sidebar can not become smaller than MIN_PART_WIDTH - const preferredEditorPartSize = this.parts.editor.preferredSize; - if (this.workbenchSize.width - this.sidebarWidth < preferredEditorPartSize.width) { - this.sidebarWidth = this.workbenchSize.width - preferredEditorPartSize.width; + if (this.workbenchSize.width - this.sidebarWidth < this.parts.editor.minimumWidth) { + this.sidebarWidth = this.workbenchSize.width - this.parts.editor.minimumWidth; } doLayout = true; diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index d1da50573984c76c02094b3b810e03a2525325ed..8e8d1e5d97eca5fc6ebb90b20a38aed3080941a8 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -14,8 +14,9 @@ import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/group/ import { IStorageService } from 'vs/platform/storage/common/storage'; import { LRUCache } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; -import { once } from 'vs/base/common/event'; +import { once, Event } from 'vs/base/common/event'; import { isEmptyObject } from 'vs/base/common/types'; +import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; /** * The base class of editors in the workbench. Editors register themselves for specific editor inputs. @@ -32,6 +33,13 @@ import { isEmptyObject } from 'vs/base/common/types'; */ export abstract class BaseEditor extends Panel implements IEditor { + readonly minimumWidth = DEFAULT_EDITOR_MIN_DIMENSIONS.width; + readonly maximumWidth = DEFAULT_EDITOR_MAX_DIMENSIONS.width; + readonly minimumHeight = DEFAULT_EDITOR_MIN_DIMENSIONS.height; + readonly maximumHeight = DEFAULT_EDITOR_MAX_DIMENSIONS.height; + + readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }> = Event.None; + private static readonly EDITOR_MEMENTOS: Map> = new Map>(); protected _input: EditorInput; diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index 74518dd76c18023123c9e9a8f383f4966b801f73..1e4336156a68f0c946e9317e5444dda730c31771 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -21,8 +21,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic export const EDITOR_TITLE_HEIGHT = 35; -export const EDITOR_MIN_DIMENSIONS = new Dimension(220, 70); -export const EDITOR_MAX_DIMENSIONS = new Dimension(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); +export const DEFAULT_EDITOR_MIN_DIMENSIONS = new Dimension(220, 70); +export const DEFAULT_EDITOR_MAX_DIMENSIONS = new Dimension(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); export interface IEditorPartOptions extends IWorkbenchEditorPartConfiguration { iconTheme?: string; diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index f74ab3e56167fc770954b555e659dd5483f44ec5..039e66bd4fd97dd1a08c9c3da09af0f5525c0a25 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -16,7 +16,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress'; import { toWinJsPromise } from 'vs/base/common/async'; -import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; +import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; export interface IOpenEditorResult { @@ -26,17 +26,24 @@ export interface IOpenEditorResult { export class EditorControl extends Disposable { + get minimumWidth() { return this._activeControl ? this._activeControl.minimumWidth : DEFAULT_EDITOR_MIN_DIMENSIONS.width; } + get minimumHeight() { return this._activeControl ? this._activeControl.minimumHeight : DEFAULT_EDITOR_MIN_DIMENSIONS.height; } + get maximumWidth() { return this._activeControl ? this._activeControl.maximumWidth : DEFAULT_EDITOR_MAX_DIMENSIONS.width; } + get maximumHeight() { return this._activeControl ? this._activeControl.maximumHeight : DEFAULT_EDITOR_MAX_DIMENSIONS.height; } + private _onDidFocus: Emitter = this._register(new Emitter()); get onDidFocus(): Event { return this._onDidFocus.event; } - private activeControlFocusListener: IDisposable; - - private dimension: Dimension; - private editorOperation: LongRunningOperation; + private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; }>()); + get onDidSizeConstraintsChange(): Event<{ width: number; height: number; }> { return this._onDidSizeConstraintsChange.event; } private _activeControl: BaseEditor; private controls: BaseEditor[] = []; + private activeControlDisposeables: IDisposable[] = []; + private dimension: Dimension; + private editorOperation: LongRunningOperation; + constructor( private parent: HTMLElement, private groupView: IEditorGroupView, @@ -76,16 +83,13 @@ export class EditorControl extends Disposable { // Create editor const control = this.doCreateEditorControl(descriptor); - // Remember editor as active - this._activeControl = control; + // Set editor as active + this.doSetActiveControl(control); // Show editor this.parent.appendChild(control.getContainer()); show(control.getContainer()); - // Track focus - this.activeControlFocusListener = control.onDidFocus(() => this._onDidFocus.fire()); - // Indicate to editor that it is now visible control.setVisible(true, this.groupView); @@ -129,6 +133,22 @@ export class EditorControl extends Disposable { return control; } + private doSetActiveControl(control: BaseEditor) { + this._activeControl = control; + + // Clear out previous active control listeners + this.activeControlDisposeables = dispose(this.activeControlDisposeables); + + // Listen to control changes + if (control) { + this.activeControlDisposeables.push(control.onDidSizeConstraintsChange(e => this._onDidSizeConstraintsChange.fire(e))); + this.activeControlDisposeables.push(control.onDidFocus(() => this._onDidFocus.fire())); + } + + // Indicate that size constraints could have changed due to new editor + this._onDidSizeConstraintsChange.fire(); + } + private doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions): TPromise { // If the input did not change, return early and only apply the options @@ -196,10 +216,7 @@ export class EditorControl extends Disposable { this._activeControl.setVisible(false, this.groupView); // Clear active control - this._activeControl = null; - - // Clear focus listener - this.activeControlFocusListener = dispose(this.activeControlFocusListener); + this.doSetActiveControl(null); } closeEditor(editor: EditorInput): void { @@ -223,7 +240,7 @@ export class EditorControl extends Disposable { } dispose(): void { - this.activeControlFocusListener = dispose(this.activeControlFocusListener); + this.activeControlDisposeables = dispose(this.activeControlDisposeables); super.dispose(); } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 0e9f49bd1512c9491d601fcb9a094cdf6144bf0c..012077d6b2dce3a6551ffe46be148159b3003900 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -9,7 +9,7 @@ import 'vs/css!./media/editorgroupview'; import { TPromise } from 'vs/base/common/winjs.base'; import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext } from 'vs/workbench/common/editor'; -import { Event, Emitter, once } from 'vs/base/common/event'; +import { Event, Emitter, once, Relay } from 'vs/base/common/event'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -34,7 +34,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RunOnceWorker } from 'vs/base/common/async'; import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; -import { IEditorGroupsAccessor, IEditorGroupView, IEditorPartOptionsChangeEvent, EDITOR_TITLE_HEIGHT, EDITOR_MIN_DIMENSIONS, EDITOR_MAX_DIMENSIONS, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor'; +import { IEditorGroupsAccessor, IEditorGroupView, IEditorPartOptionsChangeEvent, EDITOR_TITLE_HEIGHT, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { join } from 'vs/base/common/paths'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -197,6 +197,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Editor control this.editorControl = this._register(this.scopedInstantiationService.createInstance(EditorControl, this.editorContainer, this)); + this._onDidChange.input = this.editorControl.onDidSizeConstraintsChange; // Track Focus this.doTrackFocus(); @@ -1330,12 +1331,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { readonly element: HTMLElement = document.createElement('div'); - readonly minimumWidth = EDITOR_MIN_DIMENSIONS.width; - readonly minimumHeight = EDITOR_MIN_DIMENSIONS.height; - readonly maximumWidth = EDITOR_MAX_DIMENSIONS.width; - readonly maximumHeight = EDITOR_MAX_DIMENSIONS.height; + get minimumWidth(): number { return this.editorControl.minimumWidth; } + get minimumHeight(): number { return this.editorControl.minimumHeight; } + get maximumWidth(): number { return this.editorControl.maximumWidth; } + get maximumHeight(): number { return this.editorControl.maximumHeight; } - get onDidChange() { return Event.None; } // only needed if minimum sizes ever change + private _onDidChange = this._register(new Relay<{ width: number; height: number; }>()); + readonly onDidChange: Event<{ width: number; height: number; }> = this._onDidChange.event; layout(width: number, height: number): void { this.dimension = new Dimension(width, height); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index bdac02ccfd83382936f7e646523cb26d43911fec..d6a67b6b322418a6b6511f69b18d2ccc1d15a256 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -9,7 +9,7 @@ import 'vs/workbench/browser/parts/editor/editor.contribution'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Part } from 'vs/workbench/browser/part'; import { Dimension, isAncestor, toggleClass, addClass, clearNode } from 'vs/base/browser/dom'; -import { Event, Emitter, once } from 'vs/base/common/event'; +import { Event, Emitter, once, Relay, anyEvent } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument } from 'vs/workbench/services/group/common/editorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -64,6 +64,10 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor private _onDidMoveGroup: Emitter = this._register(new Emitter()); get onDidMoveGroup(): Event { return this._onDidMoveGroup.event; } + private onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; }>()); + private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; }>()); + get onDidSizeConstraintsChange(): Event<{ width: number; height: number; }> { return anyEvent(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); } + private _onDidPreferredSizeChange: Emitter = this._register(new Emitter()); get onDidPreferredSizeChange(): Event { return this._onDidPreferredSizeChange.event; } @@ -665,6 +669,11 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor //#region Part + get minimumWidth(): number { return this.gridWidget ? this.gridWidget.minimumWidth : 0; } + get maximumWidth(): number { return this.gridWidget ? this.gridWidget.maximumWidth : Number.POSITIVE_INFINITY; } + get minimumHeight(): number { return this.gridWidget ? this.gridWidget.minimumHeight : 0; } + get maximumHeight(): number { return this.gridWidget ? this.gridWidget.maximumHeight : Number.POSITIVE_INFINITY; } + get preferredSize(): Dimension { if (!this._preferredSize) { this._preferredSize = new Dimension(this.gridWidget.minimumWidth, this.gridWidget.minimumHeight); @@ -718,7 +727,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor // Grid Widget (no previous UI state or failed to restore) if (!this.gridWidget) { const initialGroup = this.doCreateGroupView(); - this.gridWidget = new SerializableGrid(initialGroup); + this.doSetGridWidget(new SerializableGrid(initialGroup)); // Ensure a group is active this.doSetGroupActive(initialGroup); @@ -749,7 +758,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor if (this.gridWidget) { clearNode(this.gridWidget.element); this.gridWidget.dispose(); - this.gridWidget = void 0; + this.doSetGridWidget(); } this.groupViews.forEach(group => group.dispose()); @@ -778,7 +787,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor } // Create new - this.gridWidget = SerializableGrid.deserialize(serializedGrid, { + this.doSetGridWidget(SerializableGrid.deserialize(serializedGrid, { fromJSON: (serializedEditorGroup: ISerializedEditorGroup) => { let groupView: IEditorGroupView; if (reuseGroupViews.length > 0) { @@ -793,7 +802,17 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor return groupView; } - }, { styles: { separatorBorder: this.gridSeparatorBorder } }); + }, { styles: { separatorBorder: this.gridSeparatorBorder } })); + } + + private doSetGridWidget(gridWidget?: SerializableGrid): void { + this.gridWidget = gridWidget; + + if (gridWidget) { + this._onDidSizeConstraintsChange.input = gridWidget.onDidChange; + } + + this.onDidSetGridWidget.fire(); } private doGetPreviousState(): IEditorPartUIState { diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 55af969883cccda05b7f73b1551913974218fa1b..21922b1f46f53857d7813e5859c8777977d7cb56 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -16,13 +16,32 @@ import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/br import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService'; import { SplitView, Sizing, Orientation } from 'vs/base/browser/ui/splitview/splitview'; -import { Event } from 'vs/base/common/event'; +import { Event, Relay, anyEvent, mapEvent, Emitter } from 'vs/base/common/event'; export class SideBySideEditor extends BaseEditor { - public static readonly ID: string = 'workbench.editor.sidebysideEditor'; + static readonly ID: string = 'workbench.editor.sidebysideEditor'; - private dimension: DOM.Dimension = new DOM.Dimension(0, 0); + get minimumMasterWidth() { return this.masterEditor ? this.masterEditor.minimumWidth : 0; } + get maximumMasterWidth() { return this.masterEditor ? this.masterEditor.maximumWidth : Number.POSITIVE_INFINITY; } + get minimumMasterHeight() { return this.masterEditor ? this.masterEditor.minimumHeight : 0; } + get maximumMasterHeight() { return this.masterEditor ? this.masterEditor.maximumHeight : Number.POSITIVE_INFINITY; } + + get minimumDetailsWidth() { return this.detailsEditor ? this.detailsEditor.minimumWidth : 0; } + get maximumDetailsWidth() { return this.detailsEditor ? this.detailsEditor.maximumWidth : Number.POSITIVE_INFINITY; } + get minimumDetailsHeight() { return this.detailsEditor ? this.detailsEditor.minimumHeight : 0; } + get maximumDetailsHeight() { return this.detailsEditor ? this.detailsEditor.maximumHeight : Number.POSITIVE_INFINITY; } + + // these setters need to exist because this extends from BaseEditor + set minimumWidth(value: number) { /* noop */ } + set maximumWidth(value: number) { /* noop */ } + set minimumHeight(value: number) { /* noop */ } + set maximumHeight(value: number) { /* noop */ } + + get minimumWidth() { return this.minimumMasterWidth + this.minimumDetailsWidth; } + get maximumWidth() { return this.maximumMasterWidth + this.maximumDetailsWidth; } + get minimumHeight() { return this.minimumMasterHeight + this.minimumDetailsHeight; } + get maximumHeight() { return this.maximumMasterHeight + this.maximumDetailsHeight; } protected masterEditor: BaseEditor; private masterEditorContainer: HTMLElement; @@ -31,6 +50,11 @@ export class SideBySideEditor extends BaseEditor { private detailsEditorContainer: HTMLElement; private splitview: SplitView; + private dimension: DOM.Dimension = new DOM.Dimension(0, 0); + + private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; }>()); + private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; }>()); + readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }> = anyEvent(this.onDidCreateEditors.event, this._onDidSizeConstraintsChange.event); constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -50,7 +74,7 @@ export class SideBySideEditor extends BaseEditor { this.detailsEditorContainer = DOM.$('.details-editor-container'); this.splitview.addView({ element: this.detailsEditorContainer, - layout: size => this.detailsEditor && this.detailsEditor.layout(new DOM.Dimension(size, this.dimension.height - 34 /* height of header container */)), + layout: size => this.detailsEditor && this.detailsEditor.layout(new DOM.Dimension(size, this.dimension.height)), minimumSize: 220, maximumSize: Number.POSITIVE_INFINITY, onDidChange: Event.None @@ -59,7 +83,7 @@ export class SideBySideEditor extends BaseEditor { this.masterEditorContainer = DOM.$('.master-editor-container'); this.splitview.addView({ element: this.masterEditorContainer, - layout: size => this.masterEditor && this.masterEditor.layout(new DOM.Dimension(size, this.dimension.height - 34 /* height of header container */)), + layout: size => this.masterEditor && this.masterEditor.layout(new DOM.Dimension(size, this.dimension.height)), minimumSize: 220, maximumSize: Number.POSITIVE_INFINITY, onDidChange: Event.None @@ -68,13 +92,13 @@ export class SideBySideEditor extends BaseEditor { this.updateStyles(); } - public setInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Thenable { + setInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Thenable { const oldInput = this.input; return super.setInput(newInput, options, token) .then(() => this.updateInput(oldInput, newInput, options, token)); } - public setOptions(options: EditorOptions): void { + setOptions(options: EditorOptions): void { if (this.masterEditor) { this.masterEditor.setOptions(options); } @@ -90,7 +114,7 @@ export class SideBySideEditor extends BaseEditor { super.setEditorVisible(visible, group); } - public clearInput(): void { + clearInput(): void { if (this.masterEditor) { this.masterEditor.clearInput(); } @@ -101,33 +125,33 @@ export class SideBySideEditor extends BaseEditor { super.clearInput(); } - public focus(): void { + focus(): void { if (this.masterEditor) { this.masterEditor.focus(); } } - public layout(dimension: DOM.Dimension): void { + layout(dimension: DOM.Dimension): void { this.dimension = dimension; this.splitview.layout(dimension.width); } - public getControl(): IEditorControl { + getControl(): IEditorControl { if (this.masterEditor) { return this.masterEditor.getControl(); } return null; } - public getMasterEditor(): IEditor { + getMasterEditor(): IEditor { return this.masterEditor; } - public getDetailsEditor(): IEditor { + getDetailsEditor(): IEditor { return this.detailsEditor; } - public supportsCenteredLayout(): boolean { + supportsCenteredLayout(): boolean { return false; } @@ -163,10 +187,18 @@ export class SideBySideEditor extends BaseEditor { private onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions, token: CancellationToken): TPromise { this.detailsEditor = details; this.masterEditor = master; + + this._onDidSizeConstraintsChange.input = anyEvent( + mapEvent(details.onDidSizeConstraintsChange, () => undefined), + mapEvent(master.onDidSizeConstraintsChange, () => undefined) + ); + + this.onDidCreateEditors.fire(); + return TPromise.join([this.detailsEditor.setInput(detailsInput, null, token), this.masterEditor.setInput(masterInput, options, token)]).then(() => this.focus()); } - public updateStyles(): void { + updateStyles(): void { super.updateStyles(); if (this.masterEditorContainer) { @@ -179,16 +211,19 @@ export class SideBySideEditor extends BaseEditor { this.detailsEditor.dispose(); this.detailsEditor = null; } + if (this.masterEditor) { this.masterEditor.dispose(); this.masterEditor = null; } + this.detailsEditorContainer.innerHTML = ''; this.masterEditorContainer.innerHTML = ''; } - public dispose(): void { + dispose(): void { this.disposeEditors(); + super.dispose(); } } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 9bc8e0542fd031c905151272467fedf94404e0a5..d19a02498593f91808a7b13280884134e10f7b26 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -58,6 +58,31 @@ export interface IEditor { */ group: IEditorGroup; + /** + * The minimum width of this editor. + */ + readonly minimumWidth: number; + + /** + * The maximum width of this editor. + */ + readonly maximumWidth: number; + + /** + * The minimum height of this editor. + */ + readonly minimumHeight: number; + + /** + * The maximum height of this editor. + */ + readonly maximumHeight: number; + + /** + * An event to notify whenever minimum/maximum width/height changes. + */ + readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }>; + /** * Returns the unique identifier of this editor. */ diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 300f905e85e60bf36bc9dd2ad92430d675778aa4..aa23dcd4ca1bbabe4df9b8df30b2ace45c3172de 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -75,6 +75,16 @@ export class PreferencesEditor extends BaseEditor { private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null; + get minimumWidth(): number { return this.sideBySidePreferencesWidget ? this.sideBySidePreferencesWidget.minimumWidth : 0; } + get maximumWidth(): number { return this.sideBySidePreferencesWidget ? this.sideBySidePreferencesWidget.maximumWidth : Number.POSITIVE_INFINITY; } + + // these setters need to exist because this extends from BaseEditor + set minimumWidth(value: number) { /*noop*/ } + set maximumWidth(value: number) { /*noop*/ } + + private _onDidCreateWidget = new Emitter<{ width: number; height: number; }>(); + readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }> = this._onDidCreateWidget.event; + constructor( @IPreferencesService private preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @@ -122,6 +132,7 @@ export class PreferencesEditor extends BaseEditor { const editorsContainer = DOM.append(parent, DOM.$('.preferences-editors-container')); this.sideBySidePreferencesWidget = this._register(this.instantiationService.createInstance(SideBySidePreferencesWidget, editorsContainer)); + this._onDidCreateWidget.fire(); this._register(this.sideBySidePreferencesWidget.onFocus(() => this.lastFocusedWidget = this.sideBySidePreferencesWidget)); this._register(this.sideBySidePreferencesWidget.onDidSettingsTargetChange(target => this.switchSettings(target))); @@ -326,6 +337,11 @@ export class PreferencesEditor extends BaseEditor { this._lastReportedFilter = filter; } } + + dispose(): void { + this._onDidCreateWidget.dispose(); + super.dispose(); + } } class SettingsNavigator extends ArrayNavigator { @@ -755,6 +771,9 @@ class SideBySidePreferencesWidget extends Widget { private lastFocusedEditor: BaseEditor; private splitview: SplitView; + get minimumWidth(): number { return this.splitview.minimumSize; } + get maximumWidth(): number { return this.splitview.maximumSize; } + constructor( parentElement: HTMLElement, @IInstantiationService private instantiationService: IInstantiationService,