Merge from vscode e74405d11443c5361c31e2bc341866d146eee206 (#8740)

This commit is contained in:
Anthony Dresser
2019-12-18 23:36:29 -08:00
committed by GitHub
parent 48dcb7258e
commit 099916bf19
109 changed files with 1327 additions and 910 deletions

View File

@@ -16,7 +16,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform';
import { PanelPositionContext } from 'vs/workbench/common/panel';
@@ -151,7 +151,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
// Panel Position
this.panelPositionContext = PanelPositionContext.bindTo(this.contextKeyService);
this.panelPositionContext.set(this.layoutService.getPanelPosition() === Position.RIGHT ? 'right' : 'bottom');
this.panelPositionContext.set(positionToString(this.layoutService.getPanelPosition()));
this.registerListeners();
}

View File

@@ -14,7 +14,7 @@ import { pathsToEditors } from 'vs/workbench/common/editor';
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { Position, Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { Position, Parts, IWorkbenchLayoutService, positionFromString, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -58,6 +58,7 @@ enum Storage {
PANEL_HIDDEN = 'workbench.panel.hidden',
PANEL_POSITION = 'workbench.panel.location',
PANEL_SIZE = 'workbench.panel.size',
PANEL_DIMENSION = 'workbench.panel.dimension',
PANEL_LAST_NON_MAXIMIZED_WIDTH = 'workbench.panel.lastNonMaximizedWidth',
PANEL_LAST_NON_MAXIMIZED_HEIGHT = 'workbench.panel.lastNonMaximizedHeight',
@@ -178,8 +179,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
position: Position.BOTTOM,
lastNonMaximizedWidth: 300,
lastNonMaximizedHeight: 300,
panelToRestore: undefined as string | undefined,
restored: false
panelToRestore: undefined as string | undefined
},
statusBar: {
@@ -571,10 +571,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
private updatePanelPosition() {
const defaultPanelPosition = this.configurationService.getValue<string>(Settings.PANEL_POSITION);
const panelPosition = this.storageService.get(Storage.PANEL_POSITION, StorageScope.WORKSPACE, undefined);
const panelPosition = this.storageService.get(Storage.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition);
this.state.panel.restored = panelPosition !== undefined;
this.state.panel.position = ((panelPosition || defaultPanelPosition) === 'right') ? Position.RIGHT : Position.BOTTOM;
this.state.panel.position = positionFromString(panelPosition || defaultPanelPosition);
}
registerPart(part: Part): void {
@@ -667,15 +666,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
getMaximumEditorDimensions(): Dimension {
const isColumn = this.state.panel.position === Position.RIGHT || this.state.panel.position === Position.LEFT;
const takenWidth =
(this.isVisible(Parts.ACTIVITYBAR_PART) ? this.activityBarPartView.minimumWidth : 0) +
(this.isVisible(Parts.SIDEBAR_PART) ? this.sideBarPartView.minimumWidth : 0) +
(this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.RIGHT ? this.panelPartView.minimumWidth : 0);
(this.isVisible(Parts.PANEL_PART) && isColumn ? this.panelPartView.minimumWidth : 0);
const takenHeight =
(this.isVisible(Parts.TITLEBAR_PART) ? this.titleBarPartView.minimumHeight : 0) +
(this.isVisible(Parts.STATUSBAR_PART) ? this.statusBarPartView.minimumHeight : 0) +
(this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.BOTTOM ? this.panelPartView.minimumHeight : 0);
(this.isVisible(Parts.PANEL_PART) && !isColumn ? this.panelPartView.minimumHeight : 0);
const availableWidth = this.dimension.width - takenWidth;
const availableHeight = this.dimension.height - takenHeight;
@@ -899,6 +899,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
: (this.state.panel.position === Position.BOTTOM ? grid.getViewSize(this.panelPartView).height : grid.getViewSize(this.panelPartView).width);
this.storageService.store(Storage.PANEL_SIZE, panelSize, StorageScope.GLOBAL);
this.storageService.store(Storage.PANEL_DIMENSION, positionToString(this.state.panel.position), StorageScope.GLOBAL);
const gridSize = grid.getViewSize();
this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL);
@@ -1202,26 +1203,18 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return this.state.panel.position;
}
setPanelPosition(position: Position.BOTTOM | Position.RIGHT): void {
setPanelPosition(position: Position): void {
if (this.state.panel.hidden) {
this.setPanelHidden(false);
}
const panelPart = this.getPart(Parts.PANEL_PART);
const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right';
const oldPositionValue = positionToString(this.state.panel.position);
const newPositionValue = positionToString(position);
this.state.panel.position = position;
function positionToString(position: Position): string {
switch (position) {
case Position.LEFT: return 'left';
case Position.RIGHT: return 'right';
case Position.BOTTOM: return 'bottom';
}
}
// Save panel position
this.storageService.store(Storage.PANEL_POSITION, positionToString(this.state.panel.position), StorageScope.WORKSPACE);
this.storageService.store(Storage.PANEL_POSITION, newPositionValue, StorageScope.WORKSPACE);
// Adjust CSS
const panelContainer = assertIsDefined(panelPart.getContainer());
@@ -1250,14 +1243,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (position === Position.BOTTOM) {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.height : this.state.panel.lastNonMaximizedHeight, this.editorPartView, Direction.Down);
} else {
} else if (position === Position.RIGHT) {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.width : this.state.panel.lastNonMaximizedWidth, this.editorPartView, Direction.Right);
} else {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.width : this.state.panel.lastNonMaximizedWidth, this.editorPartView, Direction.Left);
}
// Reset sidebar to original size before shifting the panel
this.workbenchGrid.resizeView(this.sideBarPartView, sideBarSize);
this._onPanelPositionChange.fire(positionToString(this.state.panel.position));
this._onPanelPositionChange.fire(newPositionValue);
}
isWindowMaximized() {
@@ -1275,13 +1270,26 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this._onMaximizeChange.fire(maximized);
}
private arrangeEditorNodes(editorNode: ISerializedNode, panelNode: ISerializedNode, editorSectionWidth: number): ISerializedNode[] {
switch (this.state.panel.position) {
case Position.BOTTOM:
return [{ type: 'branch', data: [editorNode, panelNode], size: editorSectionWidth }];
case Position.RIGHT:
return [editorNode, panelNode];
case Position.LEFT:
return [panelNode, editorNode];
}
}
private createGridDescriptor(): ISerializedGrid {
const workbenchDimensions = this.getClientArea();
const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width);
const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, workbenchDimensions.height);
// At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys
const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300)));
const panelSize = this.state.panel.restored ? this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, workbenchDimensions.height / 3)) : workbenchDimensions.height / 3;
const panelDimension = positionFromString(this.storageService.get(Storage.PANEL_DIMENSION, StorageScope.GLOBAL, 'bottom'));
const fallbackPanelSize = this.state.panel.position === Position.BOTTOM ? workbenchDimensions.height / 3 : workbenchDimensions.width / 4;
const panelSize = panelDimension === this.state.panel.position ? this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, fallbackPanelSize)) : fallbackPanelSize;
const titleBarHeight = this.titleBarPartView.minimumHeight;
const statusBarHeight = this.statusBarPartView.minimumHeight;
@@ -1319,9 +1327,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
visible: !this.state.panel.hidden
};
const editorSectionNode: ISerializedNode[] = this.state.panel.position === Position.BOTTOM
? [{ type: 'branch', data: [editorNode, panelNode], size: editorSectionWidth }]
: [editorNode, panelNode];
const editorSectionNode = this.arrangeEditorNodes(editorNode, panelNode, editorSectionWidth);
const middleSection: ISerializedNode[] = this.state.sideBar.position === Position.LEFT
? [activityBarNode, sideBarNode, ...editorSectionNode]

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor, IEditorPartOptions } from 'vs/workbench/common/editor';
import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor, IEditorPartOptions, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { EditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IDisposable } from 'vs/base/common/lifecycle';
@@ -63,11 +63,6 @@ export function getEditorPartOptions(config: IWorkbenchEditorConfiguration): IEd
return options;
}
export interface IEditorPartOptionsChangeEvent {
oldPartOptions: IEditorPartOptions;
newPartOptions: IEditorPartOptions;
}
export interface IEditorOpeningEvent extends IEditorIdentifier {
options?: IEditorOptions;

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/editorgroupview';
import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, toResource, SideBySideEditor, SaveReason, SaveContext } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, toResource, SideBySideEditor, SaveReason, SaveContext, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { Event, Emitter, 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';
@@ -31,7 +31,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, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';

View File

@@ -12,11 +12,11 @@ import { contrastBorder, editorBackground } from 'vs/platform/theme/common/color
import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid';
import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions } from 'vs/workbench/common/editor';
import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { values } from 'vs/base/common/map';
import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme';
import { distinct, coalesce } from 'vs/base/common/arrays';
import { IEditorGroupsAccessor, IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartOptionsChangeEvent, IEditorPartCreationOptions } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupsAccessor, IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartCreationOptions } from 'vs/workbench/browser/parts/editor/editor';
import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
@@ -110,9 +110,12 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
private readonly _onDidMoveGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidMoveGroup = this._onDidMoveGroup.event;
private onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); }
private readonly onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private readonly _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange = Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event);
private readonly _onDidEditorPartOptionsChange = this._register(new Emitter<IEditorPartOptionsChangeEvent>());
readonly onDidEditorPartOptionsChange = this._onDidEditorPartOptionsChange.event;
//#endregion
@@ -155,13 +158,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this.registerListeners();
}
//#region IEditorGroupsAccessor
private enforcedPartOptions: IEditorPartOptions[] = [];
private readonly _onDidEditorPartOptionsChange: Emitter<IEditorPartOptionsChangeEvent> = this._register(new Emitter<IEditorPartOptionsChangeEvent>());
readonly onDidEditorPartOptionsChange: Event<IEditorPartOptionsChangeEvent> = this._onDidEditorPartOptionsChange.event;
private registerListeners(): void {
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
}
@@ -185,6 +181,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this._onDidEditorPartOptionsChange.fire({ oldPartOptions, newPartOptions });
}
//#region IEditorGroupsService
private enforcedPartOptions: IEditorPartOptions[] = [];
get partOptions(): IEditorPartOptions {
return this._partOptions;
}
@@ -199,10 +199,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
});
}
//#endregion
//#region IEditorGroupsService
private _contentDimension!: Dimension;
get contentDimension(): Dimension { return this._contentDimension; }

View File

@@ -37,6 +37,15 @@
border-left-width: 0; /* no border when editor area is hiden */
}
.monaco-workbench .part.panel.left {
border-right-width: 1px;
border-right-style: solid;
}
.monaco-workbench.noeditorarea .part.panel.left {
border-right-width: 0; /* no border when editor area is hiden */
}
.monaco-workbench .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label {
outline-offset: -2px;
}
@@ -121,3 +130,10 @@
.monaco-workbench .part.panel.right .title-actions .codicon-chevron-down {
transform: rotate(-90deg);
}
/* Rotate icons when panel is on left */
.monaco-workbench .part.panel.left .title-actions .codicon-split-horizontal,
.monaco-workbench .part.panel.left .title-actions .codicon-chevron-up,
.monaco-workbench .part.panel.left .title-actions .codicon-chevron-down {
transform: rotate(90deg);
}

View File

@@ -12,11 +12,12 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchLayoutService, Parts, Position, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { ActivityAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { IActivity } from 'vs/workbench/common/activity';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
export class ClosePanelAction extends Action {
@@ -88,42 +89,6 @@ class FocusPanelAction extends Action {
}
}
export class TogglePanelPositionAction extends Action {
static readonly ID = 'workbench.action.togglePanelPosition';
static readonly LABEL = nls.localize('toggledPanelPosition', "Toggle Panel Position");
static readonly MOVE_TO_RIGHT_LABEL = nls.localize('moveToRight', "Move Panel Right");
static readonly MOVE_TO_BOTTOM_LABEL = nls.localize('moveToBottom', "Move Panel to Bottom");
private readonly toDispose = this._register(new DisposableStore());
constructor(
id: string,
label: string,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IEditorGroupsService editorGroupsService: IEditorGroupsService
) {
super(id, label, layoutService.getPanelPosition() === Position.RIGHT ? 'move-panel-to-bottom' : 'move-panel-to-right');
const setClassAndLabel = () => {
const positionRight = this.layoutService.getPanelPosition() === Position.RIGHT;
this.class = positionRight ? 'move-panel-to-bottom' : 'move-panel-to-right';
this.label = positionRight ? TogglePanelPositionAction.MOVE_TO_BOTTOM_LABEL : TogglePanelPositionAction.MOVE_TO_RIGHT_LABEL;
};
this.toDispose.add(editorGroupsService.onDidLayout(() => setClassAndLabel()));
setClassAndLabel();
}
run(): Promise<any> {
const position = this.layoutService.getPanelPosition();
this.layoutService.setPanelPosition(position === Position.BOTTOM ? Position.RIGHT : Position.BOTTOM);
return Promise.resolve();
}
}
export class ToggleMaximizedPanelAction extends Action {
@@ -160,6 +125,54 @@ export class ToggleMaximizedPanelAction extends Action {
}
}
const PositionPanelActionId = {
LEFT: 'workbench.action.positionPanelLeft',
RIGHT: 'workbench.action.positionPanelRight',
BOTTOM: 'workbench.action.positionPanelBottom',
};
interface PanelActionConfig<T> {
id: string;
when: ContextKeyExpr;
alias: string;
label: string;
value: T;
}
function createPositionPanelActionConfig(id: string, alias: string, label: string, position: Position): PanelActionConfig<Position> {
return {
id,
alias,
label,
value: position,
when: PanelPositionContext.notEqualsTo(positionToString(position))
};
}
export const PositionPanelActionConfigs = [
createPositionPanelActionConfig(PositionPanelActionId.LEFT, 'View: Panel Position Left', nls.localize('positionPanelLeft', 'Move Panel Left'), Position.LEFT),
createPositionPanelActionConfig(PositionPanelActionId.RIGHT, 'View: Panel Position Right', nls.localize('positionPanelRight', 'Move Panel Right'), Position.RIGHT),
createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, 'View: Panel Position Bottom', nls.localize('positionPanelBottom', 'Move Panel To Bottom'), Position.BOTTOM),
];
const positionByActionId = new Map(PositionPanelActionConfigs.map(config => [config.id, config.value]));
export class SetPanelPositionAction extends Action {
constructor(
id: string,
label: string,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super(id, label);
}
run(): Promise<any> {
const position = positionByActionId.get(this.id);
this.layoutService.setPanelPosition(position === undefined ? Position.BOTTOM : position);
return Promise.resolve();
}
}
export class PanelActivityAction extends ActivityAction {
constructor(
@@ -247,7 +260,6 @@ actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TogglePanelAc
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Previous Panel View', nls.localize('view', "View"));
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Next Panel View', nls.localize('view', "View"));
@@ -262,22 +274,21 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
order: 5
});
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '3_workbench_layout_move',
command: {
id: TogglePanelPositionAction.ID,
title: TogglePanelPositionAction.MOVE_TO_RIGHT_LABEL
},
when: PanelPositionContext.isEqualTo('bottom'),
order: 5
});
function registerPositionPanelActionById(config: PanelActionConfig<Position>) {
const { id, label, alias, when } = config;
// register the workbench action
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SetPanelPositionAction, id, label), alias, nls.localize('view', "View"), when);
// register as a menu item
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '3_workbench_layout_move',
command: {
id,
title: label
},
when,
order: 5
});
}
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '3_workbench_layout_move',
command: {
id: TogglePanelPositionAction.ID,
title: TogglePanelPositionAction.MOVE_TO_BOTTOM_LABEL
},
when: PanelPositionContext.isEqualTo('right'),
order: 5
});
// register each position panel action
PositionPanelActionConfigs.forEach(registerPositionPanelActionById);

View File

@@ -18,7 +18,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
import { ClosePanelAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction, PositionPanelActionConfigs, SetPanelPositionAction } from 'vs/workbench/browser/parts/panel/panelActions';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
@@ -52,7 +52,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
//#region IView
readonly minimumWidth: number = 300;
readonly minimumWidth: number = 420;
readonly maximumWidth: number = Number.POSITIVE_INFINITY;
readonly minimumHeight: number = 77;
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
@@ -122,7 +122,10 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction,
getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, assertIsDefined(this.getPanel(compositeId))),
getContextMenuActions: () => [
this.instantiationService.createInstance(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL),
...PositionPanelActionConfigs
// show the contextual menu item if it is not in that position
.filter(({ when }) => contextKeyService.contextMatchesRules(when))
.map(({ id, label }) => this.instantiationService.createInstance(SetPanelPositionAction, id, label)),
this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, localize('hidePanel', "Hide Panel"))
],
getDefaultCompositeId: () => Registry.as<PanelRegistry>(PanelExtensions.Panels).getDefaultPanelId(),
@@ -207,7 +210,9 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
const container = assertIsDefined(this.getContainer());
container.style.backgroundColor = this.getColor(PANEL_BACKGROUND) || '';
container.style.borderLeftColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || '';
const borderColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || '';
container.style.borderLeftColor = borderColor;
container.style.borderRightColor = borderColor;
const title = this.getTitleArea();
if (title) {

View File

@@ -25,7 +25,7 @@ import { PaneView, IPaneViewOptions, IPaneOptions, Pane, DefaultPaneDndControlle
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor } from 'vs/workbench/common/views';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer } from 'vs/workbench/common/views';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { assertIsDefined } from 'vs/base/common/types';
@@ -36,8 +36,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IViewPaneContainer } from 'vs/workbench/common/viewPaneContainer';
import { Component } from 'vs/workbench/common/component';
import { Extensions as ViewletExtensions, ViewletRegistry } from 'vs/workbench/browser/viewlet';
import { Extensions as PanelExtensions, PanelRegistry } from 'vs/workbench/browser/panel';
export interface IPaneColors extends IColorMapping {
dropBackground?: ColorIdentifier;
@@ -234,7 +232,8 @@ export abstract class ViewPane extends Pane implements IView {
}
export interface IViewPaneContainerOptions extends IPaneViewOptions {
showHeaderInTitleWhenSingleView: boolean;
mergeViewWithContainerWhenSingleView: boolean;
donotShowContainerTitleWhenMergedWithContainer?: boolean;
}
interface IViewPaneItem {
@@ -244,6 +243,7 @@ interface IViewPaneItem {
export class ViewPaneContainer extends Component implements IViewPaneContainer {
private readonly viewContainer: ViewContainer;
private lastFocusedPane: ViewPane | undefined;
private paneItems: IViewPaneItem[] = [];
private paneview?: PaneView;
@@ -308,6 +308,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
this.options.dnd = new DefaultPaneDndController();
}
this.viewContainer = container;
this.visibleViewsStorageId = `${id}.numberOfVisibleViews`;
this.visibleViewsCountFromCache = this.storageService.getNumber(this.visibleViewsStorageId, StorageScope.WORKSPACE, undefined);
this._register(toDisposable(() => this.viewDisposables = dispose(this.viewDisposables)));
@@ -345,15 +346,15 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
getTitle(): string {
const composite = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).getViewlet(this.getId()) || Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanel(this.getId());
let title = composite.name;
if (this.isSingleView()) {
if (this.isViewMergedWithContainer()) {
const paneItemTitle = this.paneItems[0].pane.title;
title = paneItemTitle ? `${title}: ${paneItemTitle}` : title;
if (this.options.donotShowContainerTitleWhenMergedWithContainer) {
return this.paneItems[0].pane.title;
}
return paneItemTitle ? `${this.viewContainer.name}: ${paneItemTitle}` : this.viewContainer.name;
}
return title;
return this.viewContainer.name;
}
private showContextMenu(event: StandardMouseEvent): void {
@@ -402,7 +403,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
getActions(): IAction[] {
if (this.isSingleView()) {
if (this.isViewMergedWithContainer()) {
return this.paneItems[0].pane.getActions();
}
@@ -410,7 +411,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
getSecondaryActions(): IAction[] {
if (this.isSingleView()) {
if (this.isViewMergedWithContainer()) {
return this.paneItems[0].pane.getSecondaryActions();
}
@@ -418,7 +419,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (this.isSingleView()) {
if (this.isViewMergedWithContainer()) {
return this.paneItems[0].pane.getActionViewItem(action);
}
@@ -459,14 +460,14 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
addPanes(panes: { pane: ViewPane, size: number, index?: number; }[]): void {
const wasSingleView = this.isSingleView();
const wasMerged = this.isViewMergedWithContainer();
for (const { pane: pane, size, index } of panes) {
this.addPane(pane, size, index);
}
this.updateViewHeaders();
if (this.isSingleView() !== wasSingleView) {
if (this.isViewMergedWithContainer() !== wasMerged) {
this.updateTitleArea();
}
}
@@ -643,7 +644,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
private addPane(pane: ViewPane, size: number, index = this.paneItems.length - 1): void {
const onDidFocus = pane.onDidFocus(() => this.lastFocusedPane = pane);
const onDidChangeTitleArea = pane.onDidChangeTitleArea(() => {
if (this.isSingleView()) {
if (this.isViewMergedWithContainer()) {
this.updateTitleArea();
}
});
@@ -668,12 +669,12 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
removePanes(panes: ViewPane[]): void {
const wasSingleView = this.isSingleView();
const wasMerged = this.isViewMergedWithContainer();
panes.forEach(pane => this.removePane(pane));
this.updateViewHeaders();
if (wasSingleView !== this.isSingleView()) {
if (wasMerged !== this.isViewMergedWithContainer()) {
this.updateTitleArea();
}
}
@@ -726,8 +727,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
return assertIsDefined(this.paneview).getPaneSize(pane);
}
protected updateViewHeaders(): void {
if (this.isSingleView()) {
private updateViewHeaders(): void {
if (this.isViewMergedWithContainer()) {
this.paneItems[0].pane.setExpanded(true);
this.paneItems[0].pane.headerVisible = false;
} else {
@@ -735,8 +736,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
}
protected isSingleView(): boolean {
if (!(this.options.showHeaderInTitleWhenSingleView && this.paneItems.length === 1)) {
private isViewMergedWithContainer(): boolean {
if (!(this.options.mergeViewWithContainerWhenSingleView && this.paneItems.length === 1)) {
return false;
}
if (!this.areExtensionsReady) {

View File

@@ -655,8 +655,8 @@ export class ViewsService extends Disposable implements IViewsService {
this.viewDisposable.forEach(disposable => disposable.dispose());
this.viewDisposable.clear();
}));
this._register(viewContainersRegistry.onDidRegister(viewContainer => this.onDidRegisterViewContainer(viewContainer)));
this._register(viewContainersRegistry.onDidDeregister(viewContainer => this.onDidDeregisterViewContainer(viewContainer)));
this._register(viewContainersRegistry.onDidRegister(({ viewContainer }) => this.onDidRegisterViewContainer(viewContainer)));
this._register(viewContainersRegistry.onDidDeregister(({ viewContainer }) => this.onDidDeregisterViewContainer(viewContainer)));
this._register(toDisposable(() => {
this.viewDescriptorCollections.forEach(({ disposable }) => disposable.dispose());
this.viewDescriptorCollections.clear();

View File

@@ -46,7 +46,7 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
super(viewletId, `${viewletId}.state`, { showHeaderInTitleWhenSingleView: false }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService);
super(viewletId, `${viewletId}.state`, { mergeViewWithContainerWhenSingleView: false }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService);
this._register(onDidChangeFilterValue(newFilterValue => {
this.filterValue = newFilterValue;
this.onFilterChanged(newFilterValue);

View File

@@ -174,7 +174,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
},
'workbench.panel.defaultLocation': {
'type': 'string',
'enum': ['bottom', 'right'],
'enum': ['left', 'bottom', 'right'],
'default': 'bottom',
'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom or on the right of the workbench.")
},
@@ -207,24 +207,6 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
],
'included': isMacintosh
},
'workbench.settings.enableNaturalLanguageSearch': {
'type': 'boolean',
'description': nls.localize('enableNaturalLanguageSettingsSearch', "Controls whether to enable the natural language search mode for settings. The natural language search is provided by a Microsoft online service."),
'default': true,
'scope': ConfigurationScope.WINDOW,
'tags': ['usesOnlineServices']
},
'workbench.settings.settingsSearchTocBehavior': {
'type': 'string',
'enum': ['hide', 'filter'],
'enumDescriptions': [
nls.localize('settingsSearchTocBehavior.hide', "Hide the Table of Contents while searching."),
nls.localize('settingsSearchTocBehavior.filter', "Filter the Table of Contents to just categories that have matching settings. Clicking a category will filter the results to that category."),
],
'description': nls.localize('settingsSearchTocBehavior', "Controls the behavior of the settings editor Table of Contents while searching."),
'default': 'filter',
'scope': ConfigurationScope.WINDOW
},
'workbench.settings.editor': {
'type': 'string',
'enum': ['ui', 'json'],
@@ -235,12 +217,6 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
'description': nls.localize('settings.editor.desc', "Determines which settings editor to use by default."),
'default': 'ui',
'scope': ConfigurationScope.WINDOW
},
'workbench.enableExperiments': {
'type': 'boolean',
'description': nls.localize('workbench.enableExperiments', "Fetches experiments to run from a Microsoft online service."),
'default': true,
'tags': ['usesOnlineServices']
}
}
});

View File

@@ -18,7 +18,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
import { Position, Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { Position, Parts, IWorkbenchLayoutService, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, WillSaveStateReason, StorageScope } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -349,7 +349,7 @@ export class Workbench extends Layout {
{ id: Parts.ACTIVITYBAR_PART, role: 'navigation', classes: ['activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] },
{ id: Parts.SIDEBAR_PART, role: 'complementary', classes: ['sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] },
{ id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.state.editor.restoreEditors } },
{ id: Parts.PANEL_PART, role: 'complementary', classes: ['panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right'] },
{ id: Parts.PANEL_PART, role: 'complementary', classes: ['panel', positionToString(this.state.panel.position)] },
{ id: Parts.STATUSBAR_PART, role: 'contentinfo', classes: ['statusbar'] }
].forEach(({ id, role, classes, options }) => {
const partContainer = this.createPart(id, role, classes);