Path: blob/main/src/vs/workbench/browser/parts/panel/panelPart.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import './media/panelpart.css';6import { localize } from '../../../../nls.js';7import { IAction, Separator, SubmenuAction, toAction } from '../../../../base/common/actions.js';8import { ActionsOrientation } from '../../../../base/browser/ui/actionbar/actionbar.js';9import { ActivePanelContext, PanelFocusContext } from '../../../common/contextkeys.js';10import { IWorkbenchLayoutService, Parts, Position } from '../../../services/layout/browser/layoutService.js';11import { IStorageService } from '../../../../platform/storage/common/storage.js';12import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';13import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';14import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';15import { TogglePanelAction } from './panelActions.js';16import { IThemeService } from '../../../../platform/theme/common/themeService.js';17import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BORDER, PANEL_TITLE_BADGE_BACKGROUND, PANEL_TITLE_BADGE_FOREGROUND } from '../../../common/theme.js';18import { contrastBorder } from '../../../../platform/theme/common/colorRegistry.js';19import { INotificationService } from '../../../../platform/notification/common/notification.js';20import { Dimension } from '../../../../base/browser/dom.js';21import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';22import { assertReturnsDefined } from '../../../../base/common/types.js';23import { IExtensionService } from '../../../services/extensions/common/extensions.js';24import { IViewDescriptorService } from '../../../common/views.js';25import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';26import { IMenuService, MenuId } from '../../../../platform/actions/common/actions.js';27import { AbstractPaneCompositePart, CompositeBarPosition } from '../paneCompositePart.js';28import { ICommandService } from '../../../../platform/commands/common/commands.js';29import { getContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';30import { IPaneCompositeBarOptions } from '../paneCompositeBar.js';31import { IHoverService } from '../../../../platform/hover/browser/hover.js';32import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';3334export class PanelPart extends AbstractPaneCompositePart {3536//#region IView3738readonly minimumWidth: number = 300;39readonly maximumWidth: number = Number.POSITIVE_INFINITY;40readonly minimumHeight: number = 77;41readonly maximumHeight: number = Number.POSITIVE_INFINITY;4243get preferredHeight(): number | undefined {44// Don't worry about titlebar or statusbar visibility45// The difference is minimal and keeps this function clean46return this.layoutService.mainContainerDimension.height * 0.4;47}4849get preferredWidth(): number | undefined {50const activeComposite = this.getActivePaneComposite();5152if (!activeComposite) {53return;54}5556const width = activeComposite.getOptimalWidth();57if (typeof width !== 'number') {58return;59}6061return Math.max(width, 300);62}6364//#endregion6566static readonly activePanelSettingsKey = 'workbench.panelpart.activepanelid';6768constructor(69@INotificationService notificationService: INotificationService,70@IStorageService storageService: IStorageService,71@IContextMenuService contextMenuService: IContextMenuService,72@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,73@IKeybindingService keybindingService: IKeybindingService,74@IHoverService hoverService: IHoverService,75@IInstantiationService instantiationService: IInstantiationService,76@IThemeService themeService: IThemeService,77@IViewDescriptorService viewDescriptorService: IViewDescriptorService,78@IContextKeyService contextKeyService: IContextKeyService,79@IExtensionService extensionService: IExtensionService,80@ICommandService private commandService: ICommandService,81@IMenuService menuService: IMenuService,82@IConfigurationService private configurationService: IConfigurationService83) {84super(85Parts.PANEL_PART,86{ hasTitle: true },87PanelPart.activePanelSettingsKey,88ActivePanelContext.bindTo(contextKeyService),89PanelFocusContext.bindTo(contextKeyService),90'panel',91'panel',92undefined,93PANEL_TITLE_BORDER,94notificationService,95storageService,96contextMenuService,97layoutService,98keybindingService,99hoverService,100instantiationService,101themeService,102viewDescriptorService,103contextKeyService,104extensionService,105menuService,106);107108this._register(this.configurationService.onDidChangeConfiguration(e => {109if (e.affectsConfiguration('workbench.panel.showLabels')) {110this.updateCompositeBar(true);111}112}));113}114115override updateStyles(): void {116super.updateStyles();117118const container = assertReturnsDefined(this.getContainer());119container.style.backgroundColor = this.getColor(PANEL_BACKGROUND) || '';120const borderColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || '';121container.style.borderLeftColor = borderColor;122container.style.borderRightColor = borderColor;123container.style.borderBottomColor = borderColor;124125const title = this.getTitleArea();126if (title) {127title.style.borderTopColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || '';128}129}130131protected getCompositeBarOptions(): IPaneCompositeBarOptions {132return {133partContainerClass: 'panel',134pinnedViewContainersKey: 'workbench.panel.pinnedPanels',135placeholderViewContainersKey: 'workbench.panel.placeholderPanels',136viewContainersWorkspaceStateKey: 'workbench.panel.viewContainersWorkspaceState',137icon: this.configurationService.getValue('workbench.panel.showLabels') === false,138orientation: ActionsOrientation.HORIZONTAL,139recomputeSizes: true,140activityHoverOptions: {141position: () => this.layoutService.getPanelPosition() === Position.BOTTOM && !this.layoutService.isPanelMaximized() ? HoverPosition.ABOVE : HoverPosition.BELOW,142},143fillExtraContextMenuActions: actions => this.fillExtraContextMenuActions(actions),144compositeSize: 0,145iconSize: 16,146compact: true, // Only applies to icons, not labels147overflowActionSize: 44,148colors: theme => ({149activeBackgroundColor: theme.getColor(PANEL_BACKGROUND), // Background color for overflow action150inactiveBackgroundColor: theme.getColor(PANEL_BACKGROUND), // Background color for overflow action151activeBorderBottomColor: theme.getColor(PANEL_ACTIVE_TITLE_BORDER),152activeForegroundColor: theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND),153inactiveForegroundColor: theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND),154badgeBackground: theme.getColor(PANEL_TITLE_BADGE_BACKGROUND),155badgeForeground: theme.getColor(PANEL_TITLE_BADGE_FOREGROUND),156dragAndDropBorder: theme.getColor(PANEL_DRAG_AND_DROP_BORDER)157})158};159}160161private fillExtraContextMenuActions(actions: IAction[]): void {162if (this.getCompositeBarPosition() === CompositeBarPosition.TITLE) {163const viewsSubmenuAction = this.getViewsSubmenuAction();164if (viewsSubmenuAction) {165actions.push(new Separator());166actions.push(viewsSubmenuAction);167}168}169170const panelPositionMenu = this.menuService.getMenuActions(MenuId.PanelPositionMenu, this.contextKeyService, { shouldForwardArgs: true });171const panelAlignMenu = this.menuService.getMenuActions(MenuId.PanelAlignmentMenu, this.contextKeyService, { shouldForwardArgs: true });172const positionActions = getContextMenuActions(panelPositionMenu).secondary;173const alignActions = getContextMenuActions(panelAlignMenu).secondary;174175const panelShowLabels = this.configurationService.getValue<boolean | undefined>('workbench.panel.showLabels');176const toggleShowLabelsAction = toAction({177id: 'workbench.action.panel.toggleShowLabels',178label: panelShowLabels ? localize('showIcons', "Show Icons") : localize('showLabels', "Show Labels"),179run: () => this.configurationService.updateValue('workbench.panel.showLabels', !panelShowLabels)180});181182actions.push(...[183new Separator(),184new SubmenuAction('workbench.action.panel.position', localize('panel position', "Panel Position"), positionActions),185new SubmenuAction('workbench.action.panel.align', localize('align panel', "Align Panel"), alignActions),186toggleShowLabelsAction,187toAction({ id: TogglePanelAction.ID, label: localize('hidePanel', "Hide Panel"), run: () => this.commandService.executeCommand(TogglePanelAction.ID) }),188]);189}190191override layout(width: number, height: number, top: number, left: number): void {192let dimensions: Dimension;193switch (this.layoutService.getPanelPosition()) {194case Position.RIGHT:195dimensions = new Dimension(width - 1, height); // Take into account the 1px border when layouting196break;197case Position.TOP:198dimensions = new Dimension(width, height - 1); // Take into account the 1px border when layouting199break;200default:201dimensions = new Dimension(width, height);202break;203}204205// Layout contents206super.layout(dimensions.width, dimensions.height, top, left);207}208209protected override shouldShowCompositeBar(): boolean {210return true;211}212213protected getCompositeBarPosition(): CompositeBarPosition {214return CompositeBarPosition.TITLE;215}216217toJSON(): object {218return {219type: Parts.PANEL_PART220};221}222}223224225