Path: blob/main/src/vs/workbench/browser/parts/sidebar/sidebarPart.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/sidebarpart.css';6import './sidebarActions.js';7import { ActivityBarPosition, IWorkbenchLayoutService, LayoutSettings, Parts, Position as SideBarPosition } from '../../../services/layout/browser/layoutService.js';8import { SidebarFocusContext, ActiveViewletContext } from '../../../common/contextkeys.js';9import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';10import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';11import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';12import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';13import { IThemeService } from '../../../../platform/theme/common/themeService.js';14import { contrastBorder } from '../../../../platform/theme/common/colorRegistry.js';15import { SIDE_BAR_TITLE_FOREGROUND, SIDE_BAR_TITLE_BORDER, SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND, SIDE_BAR_BORDER, SIDE_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_TOP_FOREGROUND, ACTIVITY_BAR_TOP_ACTIVE_BORDER, ACTIVITY_BAR_TOP_INACTIVE_FOREGROUND, ACTIVITY_BAR_TOP_DRAG_AND_DROP_BORDER } from '../../../common/theme.js';16import { INotificationService } from '../../../../platform/notification/common/notification.js';17import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';18import { AnchorAlignment } from '../../../../base/browser/ui/contextview/contextview.js';19import { IExtensionService } from '../../../services/extensions/common/extensions.js';20import { LayoutPriority } from '../../../../base/browser/ui/grid/grid.js';21import { assertReturnsDefined } from '../../../../base/common/types.js';22import { IViewDescriptorService } from '../../../common/views.js';23import { AbstractPaneCompositePart, CompositeBarPosition } from '../paneCompositePart.js';24import { ActivityBarCompositeBar, ActivitybarPart } from '../activitybar/activitybarPart.js';25import { ActionsOrientation } from '../../../../base/browser/ui/actionbar/actionbar.js';26import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';27import { IPaneCompositeBarOptions } from '../paneCompositeBar.js';28import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';29import { Action2, IMenuService, registerAction2 } from '../../../../platform/actions/common/actions.js';30import { Separator } from '../../../../base/common/actions.js';31import { ToggleActivityBarVisibilityActionId } from '../../actions/layoutActions.js';32import { localize2 } from '../../../../nls.js';33import { IHoverService } from '../../../../platform/hover/browser/hover.js';3435export class SidebarPart extends AbstractPaneCompositePart {3637static readonly activeViewletSettingsKey = 'workbench.sidebar.activeviewletid';3839//#region IView4041readonly minimumWidth: number = 170;42readonly maximumWidth: number = Number.POSITIVE_INFINITY;43readonly minimumHeight: number = 0;44readonly maximumHeight: number = Number.POSITIVE_INFINITY;45override get snap(): boolean { return true; }4647readonly priority: LayoutPriority = LayoutPriority.Low;4849get preferredWidth(): number | undefined {50const viewlet = this.getActivePaneComposite();5152if (!viewlet) {53return;54}5556const width = viewlet.getOptimalWidth();57if (typeof width !== 'number') {58return;59}6061return Math.max(width, 300);62}6364private readonly activityBarPart = this._register(this.instantiationService.createInstance(ActivitybarPart, this));6566//#endregion6768constructor(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@IConfigurationService private readonly configurationService: IConfigurationService,81@IMenuService menuService: IMenuService,82) {83super(84Parts.SIDEBAR_PART,85{ hasTitle: true, borderWidth: () => (this.getColor(SIDE_BAR_BORDER) || this.getColor(contrastBorder)) ? 1 : 0 },86SidebarPart.activeViewletSettingsKey,87ActiveViewletContext.bindTo(contextKeyService),88SidebarFocusContext.bindTo(contextKeyService),89'sideBar',90'viewlet',91SIDE_BAR_TITLE_FOREGROUND,92SIDE_BAR_TITLE_BORDER,93notificationService,94storageService,95contextMenuService,96layoutService,97keybindingService,98hoverService,99instantiationService,100themeService,101viewDescriptorService,102contextKeyService,103extensionService,104menuService,105);106107this.rememberActivityBarVisiblePosition();108this._register(configurationService.onDidChangeConfiguration(e => {109if (e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_LOCATION)) {110this.onDidChangeActivityBarLocation();111}112}));113114this.registerActions();115}116117private onDidChangeActivityBarLocation(): void {118this.activityBarPart.hide();119120this.updateCompositeBar();121122const id = this.getActiveComposite()?.getId();123if (id) {124this.onTitleAreaUpdate(id);125}126127if (this.shouldShowActivityBar()) {128this.activityBarPart.show();129}130131this.rememberActivityBarVisiblePosition();132}133134override updateStyles(): void {135super.updateStyles();136137const container = assertReturnsDefined(this.getContainer());138139container.style.backgroundColor = this.getColor(SIDE_BAR_BACKGROUND) || '';140container.style.color = this.getColor(SIDE_BAR_FOREGROUND) || '';141142const borderColor = this.getColor(SIDE_BAR_BORDER) || this.getColor(contrastBorder);143const isPositionLeft = this.layoutService.getSideBarPosition() === SideBarPosition.LEFT;144container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : '';145container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : '';146container.style.borderRightColor = isPositionLeft ? borderColor || '' : '';147container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : '';148container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : '';149container.style.borderLeftColor = !isPositionLeft ? borderColor || '' : '';150container.style.outlineColor = this.getColor(SIDE_BAR_DRAG_AND_DROP_BACKGROUND) ?? '';151}152153override layout(width: number, height: number, top: number, left: number): void {154if (!this.layoutService.isVisible(Parts.SIDEBAR_PART)) {155return;156}157158super.layout(width, height, top, left);159}160161protected override getTitleAreaDropDownAnchorAlignment(): AnchorAlignment {162return this.layoutService.getSideBarPosition() === SideBarPosition.LEFT ? AnchorAlignment.LEFT : AnchorAlignment.RIGHT;163}164165protected override createCompositeBar(): ActivityBarCompositeBar {166return this.instantiationService.createInstance(ActivityBarCompositeBar, this.getCompositeBarOptions(), this.partId, this, false);167}168169protected getCompositeBarOptions(): IPaneCompositeBarOptions {170return {171partContainerClass: 'sidebar',172pinnedViewContainersKey: ActivitybarPart.pinnedViewContainersKey,173placeholderViewContainersKey: ActivitybarPart.placeholderViewContainersKey,174viewContainersWorkspaceStateKey: ActivitybarPart.viewContainersWorkspaceStateKey,175icon: true,176orientation: ActionsOrientation.HORIZONTAL,177recomputeSizes: true,178activityHoverOptions: {179position: () => this.getCompositeBarPosition() === CompositeBarPosition.BOTTOM ? HoverPosition.ABOVE : HoverPosition.BELOW,180},181fillExtraContextMenuActions: actions => {182if (this.getCompositeBarPosition() === CompositeBarPosition.TITLE) {183const viewsSubmenuAction = this.getViewsSubmenuAction();184if (viewsSubmenuAction) {185actions.push(new Separator());186actions.push(viewsSubmenuAction);187}188}189},190compositeSize: 0,191iconSize: 16,192overflowActionSize: 30,193colors: theme => ({194activeBackgroundColor: theme.getColor(SIDE_BAR_BACKGROUND),195inactiveBackgroundColor: theme.getColor(SIDE_BAR_BACKGROUND),196activeBorderBottomColor: theme.getColor(ACTIVITY_BAR_TOP_ACTIVE_BORDER),197activeForegroundColor: theme.getColor(ACTIVITY_BAR_TOP_FOREGROUND),198inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_TOP_INACTIVE_FOREGROUND),199badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),200badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),201dragAndDropBorder: theme.getColor(ACTIVITY_BAR_TOP_DRAG_AND_DROP_BORDER)202}),203compact: true204};205}206207protected shouldShowCompositeBar(): boolean {208const activityBarPosition = this.configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION);209return activityBarPosition === ActivityBarPosition.TOP || activityBarPosition === ActivityBarPosition.BOTTOM;210}211212private shouldShowActivityBar(): boolean {213if (this.shouldShowCompositeBar()) {214return false;215}216217return this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) !== ActivityBarPosition.HIDDEN;218}219220protected getCompositeBarPosition(): CompositeBarPosition {221const activityBarPosition = this.configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION);222switch (activityBarPosition) {223case ActivityBarPosition.TOP: return CompositeBarPosition.TOP;224case ActivityBarPosition.BOTTOM: return CompositeBarPosition.BOTTOM;225case ActivityBarPosition.HIDDEN:226case ActivityBarPosition.DEFAULT: // noop227default: return CompositeBarPosition.TITLE;228}229}230231private rememberActivityBarVisiblePosition(): void {232const activityBarPosition = this.configurationService.getValue<string>(LayoutSettings.ACTIVITY_BAR_LOCATION);233if (activityBarPosition !== ActivityBarPosition.HIDDEN) {234this.storageService.store(LayoutSettings.ACTIVITY_BAR_LOCATION, activityBarPosition, StorageScope.PROFILE, StorageTarget.USER);235}236}237238private getRememberedActivityBarVisiblePosition(): ActivityBarPosition {239const activityBarPosition = this.storageService.get(LayoutSettings.ACTIVITY_BAR_LOCATION, StorageScope.PROFILE);240switch (activityBarPosition) {241case ActivityBarPosition.TOP: return ActivityBarPosition.TOP;242case ActivityBarPosition.BOTTOM: return ActivityBarPosition.BOTTOM;243default: return ActivityBarPosition.DEFAULT;244}245}246247override getPinnedPaneCompositeIds(): string[] {248return this.shouldShowCompositeBar() ? super.getPinnedPaneCompositeIds() : this.activityBarPart.getPinnedPaneCompositeIds();249}250251override getVisiblePaneCompositeIds(): string[] {252return this.shouldShowCompositeBar() ? super.getVisiblePaneCompositeIds() : this.activityBarPart.getVisiblePaneCompositeIds();253}254255override getPaneCompositeIds(): string[] {256return this.shouldShowCompositeBar() ? super.getPaneCompositeIds() : this.activityBarPart.getPaneCompositeIds();257}258259async focusActivityBar(): Promise<void> {260if (this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) === ActivityBarPosition.HIDDEN) {261await this.configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_LOCATION, this.getRememberedActivityBarVisiblePosition());262263this.onDidChangeActivityBarLocation();264}265266if (this.shouldShowCompositeBar()) {267this.focusCompositeBar();268} else {269if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) {270this.layoutService.setPartHidden(false, Parts.ACTIVITYBAR_PART);271}272273this.activityBarPart.show(true);274}275}276277private registerActions(): void {278const that = this;279this._register(registerAction2(class extends Action2 {280constructor() {281super({282id: ToggleActivityBarVisibilityActionId,283title: localize2('toggleActivityBar', "Toggle Activity Bar Visibility"),284});285}286run(): Promise<void> {287const value = that.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) === ActivityBarPosition.HIDDEN ? that.getRememberedActivityBarVisiblePosition() : ActivityBarPosition.HIDDEN;288return that.configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_LOCATION, value);289}290}));291}292293toJSON(): object {294return {295type: Parts.SIDEBAR_PART296};297}298}299300301