Skip to content

Commit

Permalink
Provide workbench.panel.location "top" option (microsoft#50984)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sherwyn Sen committed Mar 28, 2020
1 parent 66f0e65 commit 7afcb4b
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 23 deletions.
30 changes: 17 additions & 13 deletions src/vs/workbench/browser/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, positionFromString, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { Position, Parts, IWorkbenchLayoutService, positionFromString, positionToString, isTopOrBottom } 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';
Expand Down Expand Up @@ -916,7 +916,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi

const panelSize = this.state.panel.hidden
? grid.getViewCachedVisibleSize(this.panelPartView)
: (this.state.panel.position === Position.BOTTOM ? grid.getViewSize(this.panelPartView).height : grid.getViewSize(this.panelPartView).width);
: (isTopOrBottom(this.state.panel.position) ? 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);
Expand Down Expand Up @@ -993,8 +993,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi

this.workbenchGrid.resizeView(this.panelPartView,
{
width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0),
height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight)
width: viewSize.width + (!isTopOrBottom(this.getPanelPosition()) ? sizeChangePxWidth : 0),
height: viewSize.height + (!isTopOrBottom(this.getPanelPosition()) ? 0 : sizeChangePxHeight)
});

break;
Expand All @@ -1012,8 +1012,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
} else if (this.isVisible(Parts.PANEL_PART)) {
this.workbenchGrid.resizeView(this.editorPartView,
{
width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0),
height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight)
width: viewSize.width + (!isTopOrBottom(this.getPanelPosition()) ? sizeChangePxWidth : 0),
height: viewSize.height + (!isTopOrBottom(this.getPanelPosition()) ? 0 : sizeChangePxHeight)
});
}
} else {
Expand Down Expand Up @@ -1168,7 +1168,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const size = this.workbenchGrid.getViewSize(this.panelPartView);
if (!this.isPanelMaximized()) {
if (!this.state.panel.hidden) {
if (this.state.panel.position === Position.BOTTOM) {
if (isTopOrBottom(this.state.panel.position)) {
this.state.panel.lastNonMaximizedHeight = size.height;
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_HEIGHT, this.state.panel.lastNonMaximizedHeight, StorageScope.GLOBAL);
} else {
Expand All @@ -1180,7 +1180,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.setEditorHidden(true);
} else {
this.setEditorHidden(false);
this.workbenchGrid.resizeView(this.panelPartView, { width: this.state.panel.position === Position.BOTTOM ? size.width : this.state.panel.lastNonMaximizedWidth, height: this.state.panel.position === Position.BOTTOM ? this.state.panel.lastNonMaximizedHeight : size.height });
this.workbenchGrid.resizeView(this.panelPartView, { width: isTopOrBottom(this.state.panel.position) ? size.width : this.state.panel.lastNonMaximizedWidth, height: isTopOrBottom(this.state.panel.position) ? this.state.panel.lastNonMaximizedHeight : size.height });
this.editorGroupService.activeGroup.focus();
}
}
Expand Down Expand Up @@ -1255,15 +1255,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// 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) {
if (isTopOrBottom(position)) {
this.state.panel.lastNonMaximizedWidth = size.width;
} else if (positionFromString(oldPositionValue) === Position.BOTTOM) {
} else if (isTopOrBottom(positionFromString(oldPositionValue))) {
this.state.panel.lastNonMaximizedHeight = size.height;
}
}

if (position === Position.BOTTOM) {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.height : this.state.panel.lastNonMaximizedHeight, this.editorPartView, Direction.Down);
} else if (position === Position.TOP) {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.height : this.state.panel.lastNonMaximizedHeight, this.editorPartView, Direction.Up);
} 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 {
Expand Down Expand Up @@ -1324,6 +1326,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
switch (this.state.panel.position) {
case Position.BOTTOM:
return [{ type: 'branch', data: [editorNode, panelNode], size: editorSectionWidth }];
case Position.TOP:
return [{ type: 'branch', data: [panelNode, editorNode], size: editorSectionWidth }];
case Position.RIGHT:
return [editorNode, panelNode];
case Position.LEFT:
Expand All @@ -1338,8 +1342,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// 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 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 fallbackPanelSize = isTopOrBottom(this.state.panel.position) ? workbenchDimensions.height / 3 : workbenchDimensions.width / 4;
const panelSize = panelDimension === this.state.panel.position ? this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(isTopOrBottom(this.state.panel.position) ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, fallbackPanelSize)) : fallbackPanelSize;

const titleBarHeight = this.titleBarPartView.minimumHeight;
const statusBarHeight = this.statusBarPartView.minimumHeight;
Expand All @@ -1364,7 +1368,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const editorNode: ISerializedLeafNode = {
type: 'leaf',
data: { type: Parts.EDITOR_PART },
size: this.state.panel.position === Position.BOTTOM ?
size: isTopOrBottom(this.state.panel.position) ?
middleSectionHeight - (this.state.panel.hidden ? 0 : panelSize) :
editorSectionWidth - (this.state.panel.hidden ? 0 : panelSize),
visible: !this.state.editor.hidden
Expand Down
15 changes: 12 additions & 3 deletions src/vs/workbench/browser/parts/panel/media/panelpart.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@
}

.monaco-workbench.noeditorarea .part.panel.bottom .composite.title {
border-top-width: 0; /* no border when editor area is hiden */
border-top-width: 0; /* no border when editor area is hidden */
}

.monaco-workbench .part.panel.top .composite.title {
border-bottom-width: 1px;
border-bottom-style: solid;
}

.monaco-workbench.noeditorarea .part.panel.top .composite.title {
border-bottom-width: 0; /* no border when editor area is hidden */
}

.monaco-workbench .part.panel.right {
Expand All @@ -34,7 +43,7 @@
}

.monaco-workbench.noeditorarea .part.panel.right {
border-left-width: 0; /* no border when editor area is hiden */
border-left-width: 0; /* no border when editor area is hidden */
}

.monaco-workbench .part.panel.left {
Expand All @@ -43,7 +52,7 @@
}

.monaco-workbench.noeditorarea .part.panel.left {
border-right-width: 0; /* no border when editor area is hiden */
border-right-width: 0; /* no border when editor area is hidden */
}

.monaco-workbench .part.panel > .composite.tit > .title-actions .monaco-action-bar .action-item .action-label {
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/browser/parts/panel/panelActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const PositionPanelActionId = {
LEFT: 'workbench.action.positionPanelLeft',
RIGHT: 'workbench.action.positionPanelRight',
BOTTOM: 'workbench.action.positionPanelBottom',
TOP: 'workbench.action.positionPanelTop',
};

interface PanelActionConfig<T> {
Expand All @@ -147,6 +148,7 @@ export const PositionPanelActionConfigs: PanelActionConfig<Position>[] = [
createPositionPanelActionConfig(PositionPanelActionId.LEFT, 'View: Move Panel Left', nls.localize('positionPanelLeft', 'Move Panel Left'), Position.LEFT),
createPositionPanelActionConfig(PositionPanelActionId.RIGHT, 'View: Move Panel Right', nls.localize('positionPanelRight', 'Move Panel Right'), Position.RIGHT),
createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, 'View: Move Panel To Bottom', nls.localize('positionPanelBottom', 'Move Panel To Bottom'), Position.BOTTOM),
createPositionPanelActionConfig(PositionPanelActionId.TOP, 'View: Move Panel To Top', nls.localize('positionPanelTop', 'Move Panel To Top'), Position.TOP),
];

const positionByActionId = new Map(PositionPanelActionConfigs.map(config => [config.id, config.value]));
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/browser/parts/views/viewPaneContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { PaneView, IPaneViewOptions, IPaneOptions, Pane } from 'vs/base/browser/ui/splitview/paneview';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchLayoutService, isTopOrBottom } from 'vs/workbench/services/layout/browser/layoutService';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor } from 'vs/workbench/common/views';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
Expand Down Expand Up @@ -918,7 +918,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
if (this.viewDescriptorService.getViewContainerLocation(this.viewContainer) === ViewContainerLocation.Sidebar) {
return Orientation.VERTICAL;
} else {
return this.layoutService.getPanelPosition() === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL;
return isTopOrBottom(this.layoutService.getPanelPosition()) ? Orientation.HORIZONTAL : Orientation.VERTICAL;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/workbench.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
},
'workbench.panel.defaultLocation': {
'type': 'string',
'enum': ['left', 'bottom', 'right'],
'enum': ['left', 'bottom', 'right', 'top'],
'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, right, or left of the workbench.")
},
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/terminal/browser/terminalTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchLayoutService, Parts, Position, isTopOrBottom } from 'vs/workbench/services/layout/browser/layoutService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITerminalInstance, Direction, ITerminalTab, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
Expand Down Expand Up @@ -354,7 +354,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
if (!this._splitPaneContainer) {
this._panelPosition = this._layoutService.getPanelPosition();
this._terminalLocation = this._viewDescriptorService.getViewLocation(TERMINAL_VIEW_ID)!;
const orientation = this._terminalLocation === ViewContainerLocation.Panel && this._panelPosition === Position.BOTTOM ? Orientation.HORIZONTAL : Orientation.VERTICAL;
const orientation = this._terminalLocation === ViewContainerLocation.Panel && isTopOrBottom(this._panelPosition) ? Orientation.HORIZONTAL : Orientation.VERTICAL;
const newLocal = this._instantiationService.createInstance(SplitPaneContainer, this._tabElement, orientation);
this._splitPaneContainer = newLocal;
this.terminalInstances.forEach(instance => this._splitPaneContainer!.split(instance));
Expand Down
11 changes: 9 additions & 2 deletions src/vs/workbench/services/layout/browser/layoutService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,20 @@ export const enum Parts {
export const enum Position {
LEFT,
RIGHT,
BOTTOM
BOTTOM,
TOP
}

export function isTopOrBottom(position: Position): boolean {
return position === Position.TOP || position === Position.BOTTOM;
}

export function positionToString(position: Position): string {
switch (position) {
case Position.LEFT: return 'left';
case Position.RIGHT: return 'right';
case Position.BOTTOM: return 'bottom';
case Position.TOP: return 'top';
}

return 'bottom';
Expand All @@ -41,7 +47,8 @@ export function positionToString(position: Position): string {
const positionsByString: { [key: string]: Position } = {
[positionToString(Position.LEFT)]: Position.LEFT,
[positionToString(Position.RIGHT)]: Position.RIGHT,
[positionToString(Position.BOTTOM)]: Position.BOTTOM
[positionToString(Position.BOTTOM)]: Position.BOTTOM,
[positionToString(Position.TOP)]: Position.TOP
};

export function positionFromString(str: string): Position {
Expand Down

0 comments on commit 7afcb4b

Please sign in to comment.