Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteVen Batten <6561887+sbatten@users.noreply.github.com>2022-02-10 00:24:27 +0300
committerGitHub <noreply@github.com>2022-02-10 00:24:27 +0300
commitf80445acd5a3dadef24aa209168452a3d97cc326 (patch)
tree9aeddd537a60eb085b12d801f5cbd999d27a3aba
parent7f9be88831073b1ecefbb01fc8bdddcf2dadee27 (diff)
fixes #141349 (#142644)1.64.2release/1.64
* fixes #141349 * additional handling of the panel position with panel alignment
-rw-r--r--src/vs/platform/actions/common/actions.ts1
-rw-r--r--src/vs/workbench/browser/contextkeys.ts8
-rw-r--r--src/vs/workbench/browser/layout.ts227
-rw-r--r--src/vs/workbench/browser/layoutState.ts5
-rw-r--r--src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts3
-rw-r--r--src/vs/workbench/browser/parts/editor/editorPart.ts2
-rw-r--r--src/vs/workbench/browser/parts/panel/media/basepanelpart.css8
-rw-r--r--src/vs/workbench/browser/parts/panel/panelActions.ts67
-rw-r--r--src/vs/workbench/browser/parts/panel/panelPart.ts17
-rw-r--r--src/vs/workbench/browser/parts/views/viewPaneContainer.ts4
-rw-r--r--src/vs/workbench/browser/workbench.contribution.ts3
-rw-r--r--src/vs/workbench/browser/workbench.ts2
-rw-r--r--src/vs/workbench/contrib/terminal/browser/terminalGroup.ts15
-rw-r--r--src/vs/workbench/contrib/terminal/browser/terminalInstance.ts5
-rw-r--r--src/vs/workbench/electron-sandbox/window.ts25
-rw-r--r--src/vs/workbench/services/layout/browser/layoutService.ts16
-rw-r--r--src/vs/workbench/test/browser/workbenchTestServices.ts2
17 files changed, 307 insertions, 103 deletions
diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts
index b4d4b0a5100..25968310933 100644
--- a/src/vs/platform/actions/common/actions.ts
+++ b/src/vs/platform/actions/common/actions.ts
@@ -113,6 +113,7 @@ export class MenuId {
static readonly MenubarLayoutMenu = new MenuId('MenubarLayoutMenu');
static readonly MenubarNewBreakpointMenu = new MenuId('MenubarNewBreakpointMenu');
static readonly MenubarPanelAlignmentMenu = new MenuId('MenubarPanelAlignmentMenu');
+ static readonly MenubarPanelPositionMenu = new MenuId('MenubarPanelPositionMenu');
static readonly MenubarPreferencesMenu = new MenuId('MenubarPreferencesMenu');
static readonly MenubarRecentMenu = new MenuId('MenubarRecentMenu');
static readonly MenubarSelectionMenu = new MenuId('MenubarSelectionMenu');
diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts
index e056b85d06b..0eeba97761d 100644
--- a/src/vs/workbench/browser/contextkeys.ts
+++ b/src/vs/workbench/browser/contextkeys.ts
@@ -7,7 +7,7 @@ import { Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext } from 'vs/platform/contextkey/common/contextkeys';
-import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys';
+import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType, WebFileSystemAccess } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -15,7 +15,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
-import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
+import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { getVirtualWorkspaceScheme } from 'vs/platform/workspace/common/virtualWorkspace';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
@@ -63,6 +63,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
private isCenteredLayoutContext: IContextKey<boolean>;
private sideBarVisibleContext: IContextKey<boolean>;
private editorAreaVisibleContext: IContextKey<boolean>;
+ private panelPositionContext: IContextKey<string>;
private panelVisibleContext: IContextKey<boolean>;
private panelAlignmentContext: IContextKey<string>;
private panelMaximizedContext: IContextKey<boolean>;
@@ -179,6 +180,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.sideBarVisibleContext = SideBarVisibleContext.bindTo(this.contextKeyService);
// Panel
+ this.panelPositionContext = PanelPositionContext.bindTo(this.contextKeyService);
+ this.panelPositionContext.set(positionToString(this.layoutService.getPanelPosition()));
this.panelVisibleContext = PanelVisibleContext.bindTo(this.contextKeyService);
this.panelVisibleContext.set(this.layoutService.isVisible(Parts.PANEL_PART));
this.panelMaximizedContext = PanelMaximizedContext.bindTo(this.contextKeyService);
@@ -228,6 +231,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
this._register(this.layoutService.onDidChangeZenMode(enabled => this.inZenModeContext.set(enabled)));
this._register(this.layoutService.onDidChangeFullscreen(fullscreen => this.isFullscreenContext.set(fullscreen)));
this._register(this.layoutService.onDidChangeCenteredLayout(centered => this.isCenteredLayoutContext.set(centered)));
+ this._register(this.layoutService.onDidChangePanelPosition(position => this.panelPositionContext.set(position)));
this._register(this.layoutService.onDidChangePanelAlignment(alignment => this.panelAlignmentContext.set(alignment)));
diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts
index 35158adb130..701e29cb3bd 100644
--- a/src/vs/workbench/browser/layout.ts
+++ b/src/vs/workbench/browser/layout.ts
@@ -13,7 +13,7 @@ import { IUntypedEditorInput, pathsToEditors } from 'vs/workbench/common/editor'
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
-import { Position, Parts, PanelOpensMaximizedOptions, IWorkbenchLayoutService, positionToString, panelOpensMaximizedFromString, PanelAlignment } from 'vs/workbench/services/layout/browser/layoutService';
+import { Position, Parts, PanelOpensMaximizedOptions, IWorkbenchLayoutService, positionFromString, positionToString, panelOpensMaximizedFromString, PanelAlignment } 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';
@@ -120,6 +120,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
private readonly _onDidChangeWindowMaximized = this._register(new Emitter<boolean>());
readonly onDidChangeWindowMaximized = this._onDidChangeWindowMaximized.event;
+ private readonly _onDidChangePanelPosition = this._register(new Emitter<string>());
+ readonly onDidChangePanelPosition = this._onDidChangePanelPosition.event;
+
private readonly _onDidChangePartVisibility = this._register(new Emitter<void>());
readonly onDidChangePartVisibility = this._onDidChangePartVisibility.event;
@@ -346,6 +349,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
const oldPositionValue = (position === Position.RIGHT) ? 'left' : 'right';
const panelAlignment = this.getPanelAlignment();
+ const panelPosition = this.getPanelPosition();
this.stateModel.setRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON, position);
@@ -368,7 +372,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
auxiliaryBar.updateStyles();
// Move activity bar, side bar, and side panel
- this.adjustPartPositions(position, panelAlignment);
+ this.adjustPartPositions(position, panelAlignment, panelPosition);
}
private updateWindowBorder(skipLayout: boolean = false) {
@@ -429,6 +433,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.setSideBarPosition(change.value as Position);
}
+ if (change.key === LayoutStateKeys.PANEL_POSITION) {
+ this.setPanelPosition(change.value as Position);
+ }
+
if (change.key === LayoutStateKeys.PANEL_ALIGNMENT) {
this.setPanelAlignment(change.value as PanelAlignment);
}
@@ -987,15 +995,18 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
getMaximumEditorDimensions(): Dimension {
+ const panelPosition = this.getPanelPosition();
+ const isColumn = panelPosition === Position.RIGHT || panelPosition === 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) && isColumn ? this.panelPartView.minimumWidth : 0) +
(this.isVisible(Parts.AUXILIARYBAR_PART) ? this.auxiliaryBarPartView.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.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;
@@ -1218,7 +1229,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Panel Size
const panelSize = this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_HIDDEN)
? this.workbenchGrid.getViewCachedVisibleSize(this.panelPartView)
- : this.workbenchGrid.getViewSize(this.panelPartView).height;
+ : (this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_POSITION) === Position.BOTTOM ? this.workbenchGrid.getViewSize(this.panelPartView).height : this.workbenchGrid.getViewSize(this.panelPartView).width);
this.stateModel.setInitializationValue(LayoutStateKeys.PANEL_SIZE, panelSize as number);
// Auxiliary Bar Size
@@ -1311,8 +1322,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.workbenchGrid.resizeView(this.panelPartView,
{
- width: viewSize.width,
- height: viewSize.height + sizeChangePxHeight
+ width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0),
+ height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight)
});
break;
@@ -1451,31 +1462,43 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return viewContainerModel.activeViewDescriptors.length >= 1;
}
- private adjustPartPositions(sideBarPosition: Position, panelAlignment: PanelAlignment): void {
+ private adjustPartPositions(sideBarPosition: Position, panelAlignment: PanelAlignment, panelPosition: Position): void {
// Move activity bar, side bar, and side panel
- const sideBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.LEFT && panelAlignment === 'right') || (sideBarPosition === Position.RIGHT && panelAlignment === 'left'));
- const auxiliaryBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.RIGHT && panelAlignment === 'right') || (sideBarPosition === Position.LEFT && panelAlignment === 'left'));
+ const sideBarSiblingToEditor = panelPosition !== Position.BOTTOM || !(panelAlignment === 'center' || (sideBarPosition === Position.LEFT && panelAlignment === 'right') || (sideBarPosition === Position.RIGHT && panelAlignment === 'left'));
+ const auxiliaryBarSiblingToEditor = panelPosition !== Position.BOTTOM || !(panelAlignment === 'center' || (sideBarPosition === Position.RIGHT && panelAlignment === 'right') || (sideBarPosition === Position.LEFT && panelAlignment === 'left'));
+ const preMovePanelWidth = !this.isVisible(Parts.PANEL_PART) ? Sizing.Invisible(this.workbenchGrid.getViewCachedVisibleSize(this.panelPartView) ?? this.panelPartView.minimumWidth) : this.workbenchGrid.getViewSize(this.panelPartView).width;
+ const preMovePanelHeight = !this.isVisible(Parts.PANEL_PART) ? Sizing.Invisible(this.workbenchGrid.getViewCachedVisibleSize(this.panelPartView) ?? this.panelPartView.minimumHeight) : this.workbenchGrid.getViewSize(this.panelPartView).height;
const preMoveSideBarSize = !this.isVisible(Parts.SIDEBAR_PART) ? Sizing.Invisible(this.workbenchGrid.getViewCachedVisibleSize(this.sideBarPartView) ?? this.sideBarPartView.minimumWidth) : this.workbenchGrid.getViewSize(this.sideBarPartView).width;
const preMoveAuxiliaryBarSize = !this.isVisible(Parts.AUXILIARYBAR_PART) ? Sizing.Invisible(this.workbenchGrid.getViewCachedVisibleSize(this.auxiliaryBarPartView) ?? this.auxiliaryBarPartView.minimumWidth) : this.workbenchGrid.getViewSize(this.auxiliaryBarPartView).width;
if (sideBarPosition === Position.LEFT) {
this.workbenchGrid.moveViewTo(this.activityBarPartView, [2, 0]);
- this.workbenchGrid.moveView(this.sideBarPartView, preMoveSideBarSize, sideBarNextToEditor ? this.editorPartView : this.activityBarPartView, sideBarNextToEditor ? Direction.Left : Direction.Right);
- if (auxiliaryBarNextToEditor) {
+ this.workbenchGrid.moveView(this.sideBarPartView, preMoveSideBarSize, sideBarSiblingToEditor ? this.editorPartView : this.activityBarPartView, sideBarSiblingToEditor ? Direction.Left : Direction.Right);
+ if (auxiliaryBarSiblingToEditor) {
this.workbenchGrid.moveView(this.auxiliaryBarPartView, preMoveAuxiliaryBarSize, this.editorPartView, Direction.Right);
} else {
this.workbenchGrid.moveViewTo(this.auxiliaryBarPartView, [2, -1]);
}
} else {
this.workbenchGrid.moveViewTo(this.activityBarPartView, [2, -1]);
- this.workbenchGrid.moveView(this.sideBarPartView, preMoveSideBarSize, sideBarNextToEditor ? this.editorPartView : this.activityBarPartView, sideBarNextToEditor ? Direction.Right : Direction.Left);
- if (auxiliaryBarNextToEditor) {
+ this.workbenchGrid.moveView(this.sideBarPartView, preMoveSideBarSize, sideBarSiblingToEditor ? this.editorPartView : this.activityBarPartView, sideBarSiblingToEditor ? Direction.Right : Direction.Left);
+ if (auxiliaryBarSiblingToEditor) {
this.workbenchGrid.moveView(this.auxiliaryBarPartView, preMoveAuxiliaryBarSize, this.editorPartView, Direction.Left);
} else {
this.workbenchGrid.moveViewTo(this.auxiliaryBarPartView, [2, 0]);
}
}
+ // We moved all the side parts based on the editor and ignored the panel
+ // Now, we need to put the panel back in the right position when it is next to the editor
+ if (panelPosition !== Position.BOTTOM) {
+ this.workbenchGrid.moveView(this.panelPartView, preMovePanelWidth, this.editorPartView, panelPosition === Position.LEFT ? Direction.Left : Direction.Right);
+ this.workbenchGrid.resizeView(this.panelPartView, {
+ height: preMovePanelHeight as number,
+ width: preMovePanelWidth as number
+ });
+ }
+
// Moving views in the grid can cause them to re-distribute sizing unnecessarily
// Resize visible parts to the width they were before the operation
if (this.isVisible(Parts.SIDEBAR_PART)) {
@@ -1494,6 +1517,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
setPanelAlignment(alignment: PanelAlignment, skipLayout?: boolean): void {
+ // Panel alignment only applies to a panel in the bottom position
+ if (this.getPanelPosition() !== Position.BOTTOM) {
+ this.setPanelPosition(Position.BOTTOM);
+ }
+
// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
if (alignment !== 'center' && this.isPanelMaximized()) {
this.toggleMaximizedPanel();
@@ -1501,7 +1529,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_ALIGNMENT, alignment);
- this.adjustPartPositions(this.getSideBarPosition(), alignment);
+ this.adjustPartPositions(this.getSideBarPosition(), alignment, this.getPanelPosition());
this._onDidChangePanelAlignment.fire(alignment);
}
@@ -1582,18 +1610,23 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
toggleMaximizedPanel(): void {
const size = this.workbenchGrid.getViewSize(this.panelPartView);
+ const panelPosition = this.getPanelPosition();
const isMaximized = this.isPanelMaximized();
if (!isMaximized) {
if (this.isVisible(Parts.PANEL_PART)) {
- this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT, size.height);
+ if (panelPosition === Position.BOTTOM) {
+ this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT, size.height);
+ } else {
+ this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_WIDTH, size.width);
+ }
}
this.setEditorHidden(true);
} else {
this.setEditorHidden(false);
this.workbenchGrid.resizeView(this.panelPartView, {
- width: size.width,
- height: this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT)
+ width: panelPosition === Position.BOTTOM ? size.width : this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_WIDTH),
+ height: panelPosition === Position.BOTTOM ? this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT) : size.height
});
}
this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_WAS_LAST_MAXIMIZED, !isMaximized);
@@ -1604,7 +1637,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
*/
private panelOpensMaximized(): boolean {
// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
- if (this.getPanelAlignment() !== 'center') {
+ if (this.getPanelAlignment() !== 'center' && this.getPanelPosition() === Position.BOTTOM) {
return false;
}
@@ -1690,7 +1723,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
isPanelMaximized(): boolean {
// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
- return this.getPanelAlignment() === 'center' && !this.isVisible(Parts.EDITOR_PART);
+ return (this.getPanelAlignment() === 'center' || this.getPanelPosition() !== Position.BOTTOM) && !this.isVisible(Parts.EDITOR_PART);
}
getSideBarPosition(): Position {
@@ -1724,6 +1757,83 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.configurationService.updateValue('window.menuBarVisibility', newVisibilityValue);
}
+ getPanelPosition(): Position {
+ return this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_POSITION);
+ }
+
+ setPanelPosition(position: Position): void {
+ if (!this.isVisible(Parts.PANEL_PART)) {
+ this.setPanelHidden(false);
+ }
+
+ const panelPart = this.getPart(Parts.PANEL_PART);
+ const oldPositionValue = positionToString(this.getPanelPosition());
+ const newPositionValue = positionToString(position);
+
+ // Adjust CSS
+ const panelContainer = assertIsDefined(panelPart.getContainer());
+ panelContainer.classList.remove(oldPositionValue);
+ panelContainer.classList.add(newPositionValue);
+
+ // Update Styles
+ panelPart.updateStyles();
+
+ // Layout
+ const size = this.workbenchGrid.getViewSize(this.panelPartView);
+ const sideBarSize = this.workbenchGrid.getViewSize(this.sideBarPartView);
+ const auxiliaryBarSize = this.workbenchGrid.getViewSize(this.auxiliaryBarPartView);
+
+ let editorHidden = !this.isVisible(Parts.EDITOR_PART);
+
+ // Save last non-maximized size for panel before move
+ if (newPositionValue !== oldPositionValue && !editorHidden) {
+
+ // Save the current size of the panel for the new orthogonal direction
+ // If moving down, save the width of the panel
+ // Otherwise, save the height of the panel
+ if (position === Position.BOTTOM) {
+ this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_WIDTH, size.width);
+ } else if (positionFromString(oldPositionValue) === Position.BOTTOM) {
+ this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT, size.height);
+ }
+ }
+
+ if (position === Position.BOTTOM && this.getPanelAlignment() !== 'center' && editorHidden) {
+ this.toggleMaximizedPanel();
+ editorHidden = false;
+ }
+
+ this.stateModel.setRuntimeValue(LayoutStateKeys.PANEL_POSITION, position);
+
+ const sideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
+ const auxiliaryBarVisible = this.isVisible(Parts.AUXILIARYBAR_PART);
+
+ if (position === Position.BOTTOM) {
+ this.workbenchGrid.moveView(this.panelPartView, editorHidden ? size.height : this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_HEIGHT), this.editorPartView, Direction.Down);
+ } else if (position === Position.RIGHT) {
+ this.workbenchGrid.moveView(this.panelPartView, editorHidden ? size.width : this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_WIDTH), this.editorPartView, Direction.Right);
+ } else {
+ this.workbenchGrid.moveView(this.panelPartView, editorHidden ? size.width : this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_LAST_NON_MAXIMIZED_WIDTH), this.editorPartView, Direction.Left);
+ }
+
+ // Reset sidebar to original size before shifting the panel
+ this.workbenchGrid.resizeView(this.sideBarPartView, sideBarSize);
+ if (!sideBarVisible) {
+ this.setSideBarHidden(true);
+ }
+
+ this.workbenchGrid.resizeView(this.auxiliaryBarPartView, auxiliaryBarSize);
+ if (!auxiliaryBarVisible) {
+ this.setAuxiliaryBarHidden(true);
+ }
+
+ if (position === Position.BOTTOM) {
+ this.adjustPartPositions(this.getSideBarPosition(), this.getPanelAlignment(), position);
+ }
+
+ this._onDidChangePanelPosition.fire(newPositionValue);
+ }
+
isWindowMaximized() {
return this.windowState.runtime.maximized;
}
@@ -1811,42 +1921,62 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const panelSize = this.stateModel.getInitializationValue(LayoutStateKeys.PANEL_SIZE) ? 0 : nodes.panel.size;
const result = [] as ISerializedNode[];
- const panelAlignment = this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_ALIGNMENT);
- const sideBarPosition = this.stateModel.getRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON);
- const sideBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.LEFT && panelAlignment === 'right') || (sideBarPosition === Position.RIGHT && panelAlignment === 'left'));
- const auxiliaryBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.RIGHT && panelAlignment === 'right') || (sideBarPosition === Position.LEFT && panelAlignment === 'left'));
-
- const editorSectionWidth = availableWidth - activityBarSize - (sideBarNextToEditor ? 0 : sideBarSize) - (auxiliaryBarNextToEditor ? 0 : auxiliaryBarSize);
- result.push({
- type: 'branch',
- data: [this.arrangeEditorNodes({
- editor: nodes.editor,
- sideBar: sideBarNextToEditor ? nodes.sideBar : undefined,
- auxiliaryBar: auxiliaryBarNextToEditor ? nodes.auxiliaryBar : undefined
- }, availableHeight - panelSize, editorSectionWidth), nodes.panel],
- size: editorSectionWidth
- });
+ if (this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_POSITION) !== Position.BOTTOM) {
+ result.push(nodes.editor);
+ nodes.editor.size = availableWidth - activityBarSize - sideBarSize - panelSize - auxiliaryBarSize;
+ if (this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_POSITION) === Position.RIGHT) {
+ result.push(nodes.panel);
+ } else {
+ result.splice(0, 0, nodes.panel);
+ }
- if (!sideBarNextToEditor) {
- if (sideBarPosition === Position.LEFT) {
+ if (this.stateModel.getRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON) === Position.LEFT) {
+ result.push(nodes.auxiliaryBar);
result.splice(0, 0, nodes.sideBar);
+ result.splice(0, 0, nodes.activityBar);
} else {
+ result.splice(0, 0, nodes.auxiliaryBar);
result.push(nodes.sideBar);
+ result.push(nodes.activityBar);
}
- }
+ } else {
+ const panelAlignment = this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_ALIGNMENT);
+ const sideBarPosition = this.stateModel.getRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON);
+ const sideBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.LEFT && panelAlignment === 'right') || (sideBarPosition === Position.RIGHT && panelAlignment === 'left'));
+ const auxiliaryBarNextToEditor = !(panelAlignment === 'center' || (sideBarPosition === Position.RIGHT && panelAlignment === 'right') || (sideBarPosition === Position.LEFT && panelAlignment === 'left'));
- if (!auxiliaryBarNextToEditor) {
- if (sideBarPosition === Position.RIGHT) {
- result.splice(0, 0, nodes.auxiliaryBar);
- } else {
- result.push(nodes.auxiliaryBar);
+ const editorSectionWidth = availableWidth - activityBarSize - (sideBarNextToEditor ? 0 : sideBarSize) - (auxiliaryBarNextToEditor ? 0 : auxiliaryBarSize);
+ result.push({
+ type: 'branch',
+ data: [this.arrangeEditorNodes({
+ editor: nodes.editor,
+ sideBar: sideBarNextToEditor ? nodes.sideBar : undefined,
+ auxiliaryBar: auxiliaryBarNextToEditor ? nodes.auxiliaryBar : undefined
+ }, availableHeight - panelSize, editorSectionWidth), nodes.panel],
+ size: editorSectionWidth
+ });
+
+ if (!sideBarNextToEditor) {
+ if (sideBarPosition === Position.LEFT) {
+ result.splice(0, 0, nodes.sideBar);
+ } else {
+ result.push(nodes.sideBar);
+ }
}
- }
- if (sideBarPosition === Position.LEFT) {
- result.splice(0, 0, nodes.activityBar);
- } else {
- result.push(nodes.activityBar);
+ if (!auxiliaryBarNextToEditor) {
+ if (sideBarPosition === Position.RIGHT) {
+ result.splice(0, 0, nodes.auxiliaryBar);
+ } else {
+ result.push(nodes.auxiliaryBar);
+ }
+ }
+
+ if (sideBarPosition === Position.LEFT) {
+ result.splice(0, 0, nodes.activityBar);
+ } else {
+ result.push(nodes.activityBar);
+ }
}
return result;
@@ -1950,6 +2080,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
panelVisible: boolean;
statusbarVisible: boolean;
sideBarPosition: string;
+ panelPosition: string;
};
type StartupLayoutEventClassification = {
@@ -1959,6 +2090,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
panelVisible: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
statusbarVisible: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
sideBarPosition: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
+ panelPosition: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
};
const layoutDescriptor: StartupLayoutEvent = {
@@ -1968,6 +2100,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
panelVisible: !this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_HIDDEN),
statusbarVisible: !this.stateModel.getRuntimeValue(LayoutStateKeys.STATUSBAR_HIDDEN),
sideBarPosition: positionToString(this.stateModel.getRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON)),
+ panelPosition: positionToString(this.stateModel.getRuntimeValue(LayoutStateKeys.PANEL_POSITION)),
};
this.telemetryService.publicLog2<StartupLayoutEvent, StartupLayoutEventClassification>('startupLayout', layoutDescriptor);
diff --git a/src/vs/workbench/browser/layoutState.ts b/src/vs/workbench/browser/layoutState.ts
index edbf01b9ef4..983b9cbec15 100644
--- a/src/vs/workbench/browser/layoutState.ts
+++ b/src/vs/workbench/browser/layoutState.ts
@@ -65,6 +65,7 @@ export const LayoutStateKeys = {
// Part Positions
SIDEBAR_POSITON: new RuntimeStateKey<Position>('sideBar.position', StorageScope.GLOBAL, StorageTarget.USER, Position.LEFT),
+ PANEL_POSITION: new RuntimeStateKey<Position>('panel.position', StorageScope.WORKSPACE, StorageTarget.USER, Position.BOTTOM),
PANEL_ALIGNMENT: new RuntimeStateKey<PanelAlignment>('panel.alignment', StorageScope.GLOBAL, StorageTarget.USER, 'center'),
// Part Visibility
@@ -148,10 +149,11 @@ export class LayoutStateModel extends Disposable {
// Set dynamic defaults: part sizing and side bar visibility
const workbenchDimensions = getClientArea(this.container);
+ LayoutStateKeys.PANEL_POSITION.defaultValue = positionFromString(this.configurationService.getValue(WorkbenchLayoutSettings.PANEL_POSITION) ?? 'bottom');
LayoutStateKeys.GRID_SIZE.defaultValue = { height: workbenchDimensions.height, width: workbenchDimensions.width };
LayoutStateKeys.SIDEBAR_SIZE.defaultValue = Math.min(300, workbenchDimensions.width / 4);
LayoutStateKeys.AUXILIARYBAR_SIZE.defaultValue = Math.min(300, workbenchDimensions.width / 4);
- LayoutStateKeys.PANEL_SIZE.defaultValue = workbenchDimensions.height / 3;
+ LayoutStateKeys.PANEL_SIZE.defaultValue = (this.stateCache.get(LayoutStateKeys.PANEL_POSITION.name) ?? LayoutStateKeys.PANEL_POSITION.defaultValue) === 'bottom' ? workbenchDimensions.height / 3 : workbenchDimensions.width / 4;
LayoutStateKeys.SIDEBAR_HIDDEN.defaultValue = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
@@ -260,6 +262,7 @@ export class LayoutStateModel extends Disposable {
}
export enum WorkbenchLayoutSettings {
+ PANEL_POSITION = 'workbench.panel.defaultLocation',
PANEL_OPENS_MAXIMIZED = 'workbench.panel.opensMaximized',
ZEN_MODE_CONFIG = 'zenMode',
ZEN_MODE_SILENT_NOTIFICATIONS = 'zenMode.silentNotifications',
diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts
index 41f6a9c5846..e90911a75dc 100644
--- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts
+++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts
@@ -27,6 +27,7 @@ import { IAction, Separator, toAction } from 'vs/base/common/actions';
import { ToggleAuxiliaryBarAction } from 'vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions';
import { assertIsDefined } from 'vs/base/common/types';
import { MoveSidePanelToPanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
+import { LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
export class AuxiliaryBarPart extends BasePanelPart {
static readonly activePanelSettingsKey = 'workbench.auxiliarybar.activepanelid';
@@ -39,6 +40,8 @@ export class AuxiliaryBarPart extends BasePanelPart {
override readonly minimumHeight: number = 0;
override readonly maximumHeight: number = Number.POSITIVE_INFINITY;
+ readonly priority: LayoutPriority = LayoutPriority.Low;
+
constructor(
@INotificationService notificationService: INotificationService,
@IStorageService storageService: IStorageService,
diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts
index 5e5b04df889..1387e4d81b7 100644
--- a/src/vs/workbench/browser/parts/editor/editorPart.ts
+++ b/src/vs/workbench/browser/parts/editor/editorPart.ts
@@ -903,7 +903,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
let lastOpenHorizontalPosition: Position | undefined;
let lastOpenVerticalPosition: Position | undefined;
const openPartAtPosition = (position: Position) => {
- if (!this.layoutService.isVisible(Parts.PANEL_PART) && position === Position.BOTTOM) {
+ if (!this.layoutService.isVisible(Parts.PANEL_PART) && position === this.layoutService.getPanelPosition()) {
this.layoutService.setPartHidden(false, Parts.PANEL_PART);
} else if (!this.layoutService.isVisible(Parts.AUXILIARYBAR_PART) && position === (this.layoutService.getSideBarPosition() === Position.RIGHT ? Position.LEFT : Position.RIGHT)) {
this.layoutService.setPartHidden(false, Parts.AUXILIARYBAR_PART);
diff --git a/src/vs/workbench/browser/parts/panel/media/basepanelpart.css b/src/vs/workbench/browser/parts/panel/media/basepanelpart.css
index 250764d90d8..6cb382b8a5d 100644
--- a/src/vs/workbench/browser/parts/panel/media/basepanelpart.css
+++ b/src/vs/workbench/browser/parts/panel/media/basepanelpart.css
@@ -205,16 +205,16 @@
/* Rotate icons when panel is on right */
.monaco-workbench .part.basepanel.right .title-actions .codicon-split-horizontal::before,
-.monaco-workbench .part.basepanel.right .title-actions .codicon-panel-maximize::before,
-.monaco-workbench .part.basepanel.right .title-actions .codicon-panel-restore::before {
+.monaco-workbench .part.basepanel.right .global-actions .codicon-panel-maximize::before,
+.monaco-workbench .part.basepanel.right .global-actions .codicon-panel-restore::before {
display: inline-block;
transform: rotate(-90deg);
}
/* Rotate icons when panel is on left */
.monaco-workbench .part.basepanel.left .title-actions .codicon-split-horizontal::before,
-.monaco-workbench .part.basepanel.left .title-actions .codicon-panel-maximize::before,
-.monaco-workbench .part.basepanel.left .title-actions .codicon-panel-restore::before {
+.monaco-workbench .part.basepanel.left .global-actions .codicon-panel-maximize::before,
+.monaco-workbench .part.basepanel.left .global-actions .codicon-panel-restore::before {
display: inline-block;
transform: rotate(90deg);
}
diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts
index 9035c0b16b1..dbc5ee6b789 100644
--- a/src/vs/workbench/browser/parts/panel/panelActions.ts
+++ b/src/vs/workbench/browser/parts/panel/panelActions.ts
@@ -20,7 +20,6 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { ViewContainerLocationToString, ViewContainerLocation, IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
-import { ICommandService } from 'vs/platform/commands/common/commands';
import { INotificationService } from 'vs/platform/notification/common/notification';
const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, localize('maximizeIcon', 'Icon to maximize a panel.'));
@@ -130,10 +129,31 @@ export const AlignPanelActionConfigs: PanelActionConfig<PanelAlignment>[] = [
createAlignmentPanelActionConfig(AlignPanelActionId.JUSTIFY, 'View: Set Panel Alignment to Justify', localize('alignPanelJustify', 'Set Panel Alignment to Justify'), localize('alignPanelJustifyShort', "Justify"), 'justify'),
];
-const alignmentByActionId = new Map(AlignPanelActionConfigs.map(config => [config.id, config.value]));
+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);
+ }
+
+ override async run(): Promise<void> {
+ const position = positionByActionId.get(this.id);
+ this.layoutService.setPanelPosition(position === undefined ? Position.BOTTOM : position);
+ }
+}
+
+MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
+ submenu: MenuId.MenubarPanelPositionMenu,
+ title: localize('positionPanel', "Panel Position"),
+ group: '3_workbench_layout_move',
+ order: 4
+});
PositionPanelActionConfigs.forEach(positionPanelAction => {
- const { id, label } = positionPanelAction;
+ const { id, label, shortLabel, value, when } = positionPanelAction;
registerAction2(class extends Action2 {
constructor() {
@@ -145,17 +165,19 @@ PositionPanelActionConfigs.forEach(positionPanelAction => {
});
}
run(accessor: ServicesAccessor): void {
- const notificationService = accessor.get(INotificationService);
- const commandService = accessor.get(ICommandService);
-
- notificationService.warn(localize('deprecatedPanelMoveMessage', "Moving the panel with this command has been deprecated in favor of the \"Move Views From Panel To Side Panel\" and \"Move Views From Side Panel To Panel\" commands."));
- if (positionPanelAction.value === Position.BOTTOM) {
- commandService.executeCommand('workbench.action.moveSidePanelToPanel');
- } else {
- commandService.executeCommand('workbench.action.movePanelToSidePanel');
- }
+ const layoutService = accessor.get(IWorkbenchLayoutService);
+ layoutService.setPanelPosition(value === undefined ? Position.BOTTOM : value);
}
});
+
+ MenuRegistry.appendMenuItem(MenuId.MenubarPanelPositionMenu, {
+ command: {
+ id,
+ title: shortLabel,
+ toggled: when.negate()
+ },
+ order: 5
+ });
});
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
@@ -193,21 +215,6 @@ AlignPanelActionConfigs.forEach(alignPanelAction => {
});
});
-export class SetPanelAlignmentAction extends Action {
- constructor(
- id: string,
- label: string,
- @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
- ) {
- super(id, label);
- }
-
- override async run(): Promise<void> {
- const alignment = alignmentByActionId.get(this.id);
- this.layoutService.setPanelAlignment(alignment === undefined ? 'center' : alignment);
- }
-}
-
export class PanelActivityAction extends ActivityAction {
constructor(
@@ -331,21 +338,21 @@ registerAction2(class extends Action2 {
f1: true,
icon: maximizeIcon,
// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
- precondition: PanelAlignmentContext.isEqualTo('center'),
+ precondition: ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), PanelPositionContext.notEqualsTo('bottom')),
toggled: { condition: PanelMaximizedContext, icon: restoreIcon, tooltip: localize('minimizePanel', "Restore Panel Size") },
menu: [{
id: MenuId.PanelTitle,
group: 'navigation',
order: 1,
// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
- when: PanelAlignmentContext.isEqualTo('center')
+ when: ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), PanelPositionContext.notEqualsTo('bottom'))
}]
});
}
run(accessor: ServicesAccessor) {
const layoutService = accessor.get(IWorkbenchLayoutService);
const notificationService = accessor.get(INotificationService);
- if (layoutService.getPanelAlignment() !== 'center') {
+ if (layoutService.getPanelAlignment() !== 'center' && layoutService.getPanelPosition() === Position.BOTTOM) {
notificationService.warn(localize('panelMaxNotSupported', "Maximizing the panel is only supported when it is center aligned."));
return;
}
diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts
index 69da4553060..c72e81f9831 100644
--- a/src/vs/workbench/browser/parts/panel/panelPart.ts
+++ b/src/vs/workbench/browser/parts/panel/panelPart.ts
@@ -12,13 +12,13 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActivePanelContext, PanelFocusContext, getEnabledViewContainerContextKey } from 'vs/workbench/common/contextkeys';
import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/compositePart';
-import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
+import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
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 { PanelActivityAction, TogglePanelAction, PlaceHolderPanelActivityAction, PlaceHolderToggleCompositePinnedAction, MovePanelToSidePanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
+import { PanelActivityAction, TogglePanelAction, PlaceHolderPanelActivityAction, PlaceHolderToggleCompositePinnedAction, PositionPanelActionConfigs, SetPanelPositionAction, MovePanelToSidePanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_INPUT_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, PANEL_DRAG_AND_DROP_BORDER } from 'vs/workbench/common/theme';
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
@@ -930,7 +930,7 @@ export class PanelPart extends BasePanelPart {
protected getActivityHoverOptions(): IActivityHoverOptions {
return {
- position: () => !this.layoutService.isPanelMaximized() ? HoverPosition.ABOVE : HoverPosition.BELOW,
+ position: () => this.layoutService.getPanelPosition() === Position.BOTTOM && !this.layoutService.isPanelMaximized() ? HoverPosition.ABOVE : HoverPosition.BELOW,
};
}
@@ -939,6 +939,10 @@ export class PanelPart extends BasePanelPart {
actions.push(...[
new Separator(),
toAction({ id: MovePanelToSidePanelAction.ID, label: localize('moveToSidePanel', "Move Views to Side Panel"), run: () => this.instantiationService.invokeFunction(accessor => new MovePanelToSidePanelAction().run(accessor)) }),
+ ...PositionPanelActionConfigs
+ // show the contextual menu item if it is not in that position
+ .filter(({ when }) => this.contextKeyService.contextMatchesRules(when))
+ .map(({ id, label }) => this.instantiationService.createInstance(SetPanelPositionAction, id, label)),
this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, localize('hidePanel', "Hide Panel"))
]);
}
@@ -966,7 +970,12 @@ export class PanelPart extends BasePanelPart {
}
override layout(width: number, height: number, top: number, left: number): void {
- const dimensions = new Dimension(width, height);
+ let dimensions: Dimension;
+ if (this.layoutService.getPanelPosition() === Position.RIGHT) {
+ dimensions = new Dimension(width - 1, height); // Take into account the 1px border when layouting
+ } else {
+ dimensions = new Dimension(width, height);
+ }
// Layout contents
super.layout(dimensions.width, dimensions.height, top, left);
diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts
index 17e0b2b1d6e..0c01b54a8f9 100644
--- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts
+++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts
@@ -39,7 +39,7 @@ import { PANEL_SECTION_BORDER, PANEL_SECTION_DRAG_AND_DROP_BACKGROUND, PANEL_SEC
import { IAddedViewDescriptorRef, ICustomViewDescriptor, IView, IViewContainerModel, IViewDescriptor, IViewDescriptorRef, IViewDescriptorService, IViewPaneContainer, IViewsService, ViewContainer, ViewContainerLocation, ViewContainerLocationToString, ViewVisibilityState } from 'vs/workbench/common/views';
import { FocusedViewContext } from 'vs/workbench/common/contextkeys';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
-import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
+import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
export const ViewsSubMenu = new MenuId('Views');
MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, <ISubmenuItem>{
@@ -617,7 +617,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
case ViewContainerLocation.AuxiliaryBar:
return Orientation.VERTICAL;
case ViewContainerLocation.Panel:
- return Orientation.HORIZONTAL;
+ return this.layoutService.getPanelPosition() === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL;
}
return Orientation.VERTICAL;
diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts
index aa8b60656e7..bf561fbf839 100644
--- a/src/vs/workbench/browser/workbench.contribution.ts
+++ b/src/vs/workbench/browser/workbench.contribution.ts
@@ -285,8 +285,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
'type': 'string',
'enum': ['left', 'bottom', 'right'],
'default': 'bottom',
- 'description': localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom, right, or left of the workbench."),
- 'deprecationMessage': localize('panelDefaultLocationDeprecated', "This setting has been deprecated with the addition of the new side panel. Instead of setting the location for the panel, you now use the \"Move Views\" commands to set the location of the individual view containers within the panels.")
+ 'description': localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems) in a new workspace. It can either show at the bottom, right, or left of the editor area."),
},
'workbench.panel.opensMaximized': {
'type': 'string',
diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts
index c6755a2a284..0ab5bac6b82 100644
--- a/src/vs/workbench/browser/workbench.ts
+++ b/src/vs/workbench/browser/workbench.ts
@@ -342,7 +342,7 @@ export class Workbench extends Layout {
{ id: Parts.ACTIVITYBAR_PART, role: 'none', classes: ['activitybar', this.getSideBarPosition() === Position.LEFT ? 'left' : 'right'] }, // Use role 'none' for some parts to make screen readers less chatty #114892
{ id: Parts.SIDEBAR_PART, role: 'none', classes: ['sidebar', this.getSideBarPosition() === Position.LEFT ? 'left' : 'right'] },
{ id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.willRestoreEditors() } },
- { id: Parts.PANEL_PART, role: 'none', classes: ['panel', 'basepanel', positionToString(Position.BOTTOM)] },
+ { id: Parts.PANEL_PART, role: 'none', classes: ['panel', 'basepanel', positionToString(this.getPanelPosition())] },
{ id: Parts.AUXILIARYBAR_PART, role: 'none', classes: ['auxiliarybar', 'basepanel', this.getSideBarPosition() === Position.LEFT ? 'right' : 'left'] },
{ id: Parts.STATUSBAR_PART, role: 'status', classes: ['statusbar'] }
].forEach(({ id, role, classes, options }) => {
diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts
index 4a6d2c182e1..357c121317f 100644
--- a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts
+++ b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts
@@ -7,7 +7,7 @@ import { TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
-import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
+import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITerminalInstance, Direction, ITerminalGroup, ITerminalService, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
@@ -246,6 +246,7 @@ export class TerminalGroup extends Disposable implements ITerminalGroup {
private _terminalInstances: ITerminalInstance[] = [];
private _splitPaneContainer: SplitPaneContainer | undefined;
private _groupElement: HTMLElement | undefined;
+ private _panelPosition: Position = Position.BOTTOM;
private _terminalLocation: ViewContainerLocation = ViewContainerLocation.Panel;
private _instanceDisposables: Map<number, IDisposable[]> = new Map();
@@ -276,6 +277,7 @@ export class TerminalGroup extends Disposable implements ITerminalGroup {
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance | undefined,
@ITerminalService private readonly _terminalService: ITerminalService,
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
+ @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
@@ -286,7 +288,7 @@ export class TerminalGroup extends Disposable implements ITerminalGroup {
if (this._container) {
this.attachToElement(this._container);
}
- this._onPanelOrientationChanged.fire(this._terminalLocation === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL);
+ this._onPanelOrientationChanged.fire(this._terminalLocation === ViewContainerLocation.Panel && this._panelPosition === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL);
}
addInstance(shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance, parentTerminalId?: number): void {
@@ -466,8 +468,9 @@ export class TerminalGroup extends Disposable implements ITerminalGroup {
this._container.appendChild(this._groupElement);
if (!this._splitPaneContainer) {
+ this._panelPosition = this._layoutService.getPanelPosition();
this._terminalLocation = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID)!;
- const orientation = this._terminalLocation === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL;
+ const orientation = this._terminalLocation === ViewContainerLocation.Panel && this._panelPosition === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL;
this._splitPaneContainer = this._instantiationService.createInstance(SplitPaneContainer, this._groupElement, orientation);
this.terminalInstances.forEach(instance => this._splitPaneContainer!.split(instance, this._activeInstanceIndex + 1));
if (this._initialRelativeSizes) {
@@ -529,11 +532,13 @@ export class TerminalGroup extends Disposable implements ITerminalGroup {
layout(width: number, height: number): void {
if (this._splitPaneContainer) {
// Check if the panel position changed and rotate panes if so
+ const newPanelPosition = this._layoutService.getPanelPosition();
const newTerminalLocation = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID)!;
- const terminalPositionChanged = newTerminalLocation !== this._terminalLocation;
+ const terminalPositionChanged = newPanelPosition !== this._panelPosition || newTerminalLocation !== this._terminalLocation;
if (terminalPositionChanged) {
- const newOrientation = newTerminalLocation === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL;
+ const newOrientation = newTerminalLocation === ViewContainerLocation.Panel && newPanelPosition === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL;
this._splitPaneContainer.setOrientation(newOrientation);
+ this._panelPosition = newPanelPosition;
this._terminalLocation = newTerminalLocation;
this._onPanelOrientationChanged.fire(this._splitPaneContainer.orientation);
}
diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
index d8b6b5fd730..00064038b7d 100644
--- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
+++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
@@ -51,6 +51,7 @@ import { URI } from 'vs/base/common/uri';
import { DataTransfers } from 'vs/base/browser/dnd';
import { CodeDataTransfers, containsDragType, DragAndDropObserver, IDragAndDropObserverCallbacks } from 'vs/workbench/browser/dnd';
import { getColorClass, getColorStyleElement, getStandardColors } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
+import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
@@ -2064,6 +2065,7 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
constructor(
private readonly _container: HTMLElement,
+ @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
) {
super();
@@ -2174,8 +2176,9 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
}
private _getViewOrientation(): Orientation {
+ const panelPosition = this._layoutService.getPanelPosition();
const terminalLocation = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID);
- return terminalLocation === ViewContainerLocation.Panel
+ return terminalLocation === ViewContainerLocation.Panel && panelPosition === Position.BOTTOM
? Orientation.HORIZONTAL
: Orientation.VERTICAL;
}
diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts
index 763c8d02384..f831821d163 100644
--- a/src/vs/workbench/electron-sandbox/window.ts
+++ b/src/vs/workbench/electron-sandbox/window.ts
@@ -13,7 +13,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { EditorResourceAccessor, IUntitledTextResourceEditorInput, SideBySideEditor, pathsToEditors, IResourceDiffEditorInput, IUntypedEditorInput } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-import { IOpenFileRequest, IWindowsConfiguration, getTitleBarStyle, IAddFoldersRequest, INativeRunActionInWindowRequest, INativeRunKeybindingInWindowRequest, INativeOpenFileRequest } from 'vs/platform/windows/common/windows';
+import { WindowMinimumSize, IOpenFileRequest, IWindowsConfiguration, getTitleBarStyle, IAddFoldersRequest, INativeRunActionInWindowRequest, INativeRunKeybindingInWindowRequest, INativeOpenFileRequest } from 'vs/platform/windows/common/windows';
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { applyZoom } from 'vs/platform/windows/electron-sandbox/window';
@@ -47,7 +47,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { posix, dirname } from 'vs/base/common/path';
import { getBaseLabel } from 'vs/base/common/labels';
import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/platform/tunnel/common/tunnel';
-import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
+import { IWorkbenchLayoutService, Parts, positionFromString, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
@@ -312,6 +312,10 @@ export class NativeWindow extends Disposable {
this.onDidChangeWindowMaximized(this.environmentService.configuration.maximized ?? false);
+ // Detect panel position to determine minimum width
+ this._register(this.layoutService.onDidChangePanelPosition(pos => this.onDidChangePanelPosition(positionFromString(pos))));
+ this.onDidChangePanelPosition(this.layoutService.getPanelPosition());
+
// Lifecycle
this._register(this.lifecycleService.onBeforeShutdownError(e => this.onBeforeShutdownError(e)));
this._register(this.lifecycleService.onWillShutdown((e) => this.onWillShutdown(e)));
@@ -397,6 +401,23 @@ export class NativeWindow extends Disposable {
this.layoutService.updateWindowMaximizedState(maximized);
}
+ private getWindowMinimumWidth(panelPosition: Position = this.layoutService.getPanelPosition()): number {
+
+ // if panel is on the side, then return the larger minwidth
+ const panelOnSide = panelPosition === Position.LEFT || panelPosition === Position.RIGHT;
+ if (panelOnSide) {
+ return WindowMinimumSize.WIDTH_WITH_VERTICAL_PANEL;
+ }
+
+ return WindowMinimumSize.WIDTH;
+ }
+
+ private onDidChangePanelPosition(pos: Position): void {
+ const minWidth = this.getWindowMinimumWidth(pos);
+
+ this.nativeHostService.setMinimumSize(minWidth, undefined);
+ }
+
private onDidChangeVisibleEditors(): void {
// Close when empty: check if we should close the window based on the setting
diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts
index 4120a59a8a2..c7b7ecba631 100644
--- a/src/vs/workbench/services/layout/browser/layoutService.ts
+++ b/src/vs/workbench/services/layout/browser/layoutService.ts
@@ -99,6 +99,11 @@ export interface IWorkbenchLayoutService extends ILayoutService {
*/
readonly onDidChangeCenteredLayout: Event<boolean>;
+ /*
+ * Emit when panel position changes.
+ */
+ readonly onDidChangePanelPosition: Event<string>;
+
/**
* Emit when panel alignment changes.
*/
@@ -201,8 +206,17 @@ export interface IWorkbenchLayoutService extends ILayoutService {
*/
toggleMenuBar(): void;
+ /*
+ * Gets the current panel position. Note that the panel can be hidden too.
+ */
+ getPanelPosition(): Position;
+
+ /**
+ * Sets the panel position.
+ */
+ setPanelPosition(position: Position): void;
+
/**
- *
* Gets the panel alignement.
*/
getPanelAlignment(): PanelAlignment;
diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts
index 733bf64f861..87b2cf90c31 100644
--- a/src/vs/workbench/test/browser/workbenchTestServices.ts
+++ b/src/vs/workbench/test/browser/workbenchTestServices.ts
@@ -544,6 +544,7 @@ export class TestLayoutService implements IWorkbenchLayoutService {
onDidChangeCenteredLayout: Event<boolean> = Event.None;
onDidChangeFullscreen: Event<boolean> = Event.None;
onDidChangeWindowMaximized: Event<boolean> = Event.None;
+ onDidChangePanelPosition: Event<string> = Event.None;
onDidChangePanelAlignment: Event<PanelAlignment> = Event.None;
onDidChangePartVisibility: Event<void> = Event.None;
onDidLayout = Event.None;
@@ -578,6 +579,7 @@ export class TestLayoutService implements IWorkbenchLayoutService {
getMenubarVisibility(): MenuBarVisibility { throw new Error('not implemented'); }
toggleMenuBar(): void { }
getSideBarPosition() { return 0; }
+ getPanelPosition() { return 0; }
getPanelAlignment(): PanelAlignment { return 'center'; }
async setPanelPosition(_position: PartPosition): Promise<void> { }
async setPanelAlignment(_alignment: PanelAlignment): Promise<void> { }