Path: blob/main/src/vs/workbench/browser/parts/panel/panelPart.ts
5284 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 undefined;54}5556const width = activeComposite.getOptimalWidth();57if (typeof width !== 'number') {58return undefined;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, trailingSeparator: 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;124125if (this.titleArea) {126this.titleArea.style.borderTopColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || '';127}128}129130protected getCompositeBarOptions(): IPaneCompositeBarOptions {131return {132partContainerClass: 'panel',133pinnedViewContainersKey: 'workbench.panel.pinnedPanels',134placeholderViewContainersKey: 'workbench.panel.placeholderPanels',135viewContainersWorkspaceStateKey: 'workbench.panel.viewContainersWorkspaceState',136icon: this.configurationService.getValue('workbench.panel.showLabels') === false,137orientation: ActionsOrientation.HORIZONTAL,138recomputeSizes: true,139activityHoverOptions: {140position: () => this.layoutService.getPanelPosition() === Position.BOTTOM && !this.layoutService.isPanelMaximized() ? HoverPosition.ABOVE : HoverPosition.BELOW,141},142fillExtraContextMenuActions: actions => this.fillExtraContextMenuActions(actions),143compositeSize: 0,144iconSize: 16,145compact: true, // Only applies to icons, not labels146overflowActionSize: 44,147colors: theme => ({148activeBackgroundColor: theme.getColor(PANEL_BACKGROUND), // Background color for overflow action149inactiveBackgroundColor: theme.getColor(PANEL_BACKGROUND), // Background color for overflow action150activeBorderBottomColor: theme.getColor(PANEL_ACTIVE_TITLE_BORDER),151activeForegroundColor: theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND),152inactiveForegroundColor: theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND),153badgeBackground: theme.getColor(PANEL_TITLE_BADGE_BACKGROUND),154badgeForeground: theme.getColor(PANEL_TITLE_BADGE_FOREGROUND),155dragAndDropBorder: theme.getColor(PANEL_DRAG_AND_DROP_BORDER)156})157};158}159160private fillExtraContextMenuActions(actions: IAction[]): void {161if (this.getCompositeBarPosition() === CompositeBarPosition.TITLE) {162const viewsSubmenuAction = this.getViewsSubmenuAction();163if (viewsSubmenuAction) {164actions.push(new Separator());165actions.push(viewsSubmenuAction);166}167}168169const panelPositionMenu = this.menuService.getMenuActions(MenuId.PanelPositionMenu, this.contextKeyService, { shouldForwardArgs: true });170const panelAlignMenu = this.menuService.getMenuActions(MenuId.PanelAlignmentMenu, this.contextKeyService, { shouldForwardArgs: true });171const positionActions = getContextMenuActions(panelPositionMenu).secondary;172const alignActions = getContextMenuActions(panelAlignMenu).secondary;173174const panelShowLabels = this.configurationService.getValue<boolean | undefined>('workbench.panel.showLabels');175const toggleShowLabelsAction = toAction({176id: 'workbench.action.panel.toggleShowLabels',177label: panelShowLabels ? localize('showIcons', "Show Icons") : localize('showLabels', "Show Labels"),178run: () => this.configurationService.updateValue('workbench.panel.showLabels', !panelShowLabels)179});180181actions.push(...[182new Separator(),183new SubmenuAction('workbench.action.panel.position', localize('panel position', "Panel Position"), positionActions),184new SubmenuAction('workbench.action.panel.align', localize('align panel', "Align Panel"), alignActions),185toggleShowLabelsAction,186toAction({ id: TogglePanelAction.ID, label: localize('hidePanel', "Hide Panel"), run: () => this.commandService.executeCommand(TogglePanelAction.ID) }),187]);188}189190override layout(width: number, height: number, top: number, left: number): void {191let dimensions: Dimension;192switch (this.layoutService.getPanelPosition()) {193case Position.RIGHT:194dimensions = new Dimension(width - 1, height); // Take into account the 1px border when layouting195break;196case Position.TOP:197dimensions = new Dimension(width, height - 1); // Take into account the 1px border when layouting198break;199default:200dimensions = new Dimension(width, height);201break;202}203204// Layout contents205super.layout(dimensions.width, dimensions.height, top, left);206}207208protected override shouldShowCompositeBar(): boolean {209return true;210}211212protected getCompositeBarPosition(): CompositeBarPosition {213return CompositeBarPosition.TITLE;214}215216toJSON(): object {217return {218type: Parts.PANEL_PART219};220}221}222223224