statusbar: generalize style overrides

cc @bpasero @isidorn
This commit is contained in:
Joao Moreno
2022-01-17 17:10:51 +01:00
parent d3bb6d7a9c
commit 9be157b386
3 changed files with 66 additions and 69 deletions
@@ -5,11 +5,11 @@
import 'vs/css!./media/statusbarpart';
import { localize } from 'vs/nls';
import { DisposableStore, dispose, MutableDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, dispose, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Part } from 'vs/workbench/browser/part';
import { EventType as TouchEventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/browser/statusbar';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarStyleOverride } from 'vs/workbench/services/statusbar/browser/statusbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IAction, Separator, toAction } from 'vs/base/common/actions';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
@@ -96,6 +96,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
}(this.configurationService, this.hoverService);
private readonly compactEntriesDisposable = this._register(new MutableDisposable<DisposableStore>());
private readonly styleOverrides = new Set<IStatusbarStyleOverride>();
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -498,14 +499,15 @@ export class StatusbarPart extends Part implements IStatusbarService {
super.updateStyles();
const container = assertIsDefined(this.getContainer());
const styleOverride: IStatusbarStyleOverride | undefined = [...this.styleOverrides].sort((a, b) => a.priority - b.priority)[0];
// Background colors
const backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND) || '';
const backgroundColor = this.getColor(styleOverride?.background ?? (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND)) || '';
container.style.backgroundColor = backgroundColor;
container.style.color = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND) || '';
container.style.color = this.getColor(styleOverride?.foreground ?? (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)) || '';
// Border color
const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder);
const borderColor = this.getColor(styleOverride?.border ?? (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER)) || this.getColor(contrastBorder);
if (borderColor) {
container.classList.add('status-border-top');
container.style.setProperty('--status-border-top-color', borderColor.toString());
@@ -527,6 +529,16 @@ export class StatusbarPart extends Part implements IStatusbarService {
super.layoutContents(width, height);
}
overrideStyle(style: IStatusbarStyleOverride): IDisposable {
this.styleOverrides.add(style);
this.updateStyles();
return toDisposable(() => {
this.styleOverrides.delete(style);
this.updateStyles();
});
}
toJSON(): object {
return {
type: Parts.STATUSBAR_PART
@@ -3,16 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { localize } from 'vs/nls';
import { registerColor, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IDebugService, State, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_BORDER } from 'vs/workbench/common/theme';
import { assertIsDefined } from 'vs/base/common/types';
import { createStyleSheet } from 'vs/base/browser/dom';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { STATUS_BAR_FOREGROUND, STATUS_BAR_BORDER } from 'vs/workbench/common/theme';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { IStatusbarService } from 'vs/workbench/services/statusbar/browser/statusbar';
// colors for theming
@@ -34,72 +32,46 @@ export const STATUS_BAR_DEBUGGING_BORDER = registerColor('statusBar.debuggingBor
hc: STATUS_BAR_BORDER
}, localize('statusBarDebuggingBorder', "Status bar border color separating to the sidebar and editor when a program is being debugged. The status bar is shown in the bottom of the window"));
export class StatusBarColorProvider extends Themable implements IWorkbenchContribution {
private styleElement: HTMLStyleElement | undefined;
export class StatusBarColorProvider implements IWorkbenchContribution {
private readonly disposables = new DisposableStore();
private disposable: IDisposable | undefined;
private set enabled(enabled: boolean) {
if (enabled === !!this.disposable) {
return;
}
if (enabled) {
this.disposable = this.statusbarService.overrideStyle({
priority: 100,
foreground: STATUS_BAR_DEBUGGING_FOREGROUND,
background: STATUS_BAR_DEBUGGING_BACKGROUND,
border: STATUS_BAR_DEBUGGING_BORDER,
});
} else {
this.disposable!.dispose();
this.disposable = undefined;
}
}
constructor(
@IThemeService themeService: IThemeService,
@IDebugService private readonly debugService: IDebugService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
@IStatusbarService private readonly statusbarService: IStatusbarService
) {
super(themeService);
this.registerListeners();
this.updateStyles();
this.debugService.onDidChangeState(this.update, this, this.disposables);
this.contextService.onDidChangeWorkbenchState(this.update, this, this.disposables);
this.update();
}
private registerListeners(): void {
this._register(this.debugService.onDidChangeState(state => this.updateStyles()));
this._register(this.contextService.onDidChangeWorkbenchState(state => this.updateStyles()));
protected update(): void {
this.enabled = isStatusbarInDebugMode(this.debugService.state, this.debugService.getViewModel().focusedSession);
}
protected override updateStyles(): void {
super.updateStyles();
const container = assertIsDefined(this.layoutService.getContainer(Parts.STATUSBAR_PART));
if (isStatusbarInDebugMode(this.debugService.state, this.debugService.getViewModel().focusedSession)) {
container.classList.add('debugging');
} else {
container.classList.remove('debugging');
}
// Container Colors
const backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND));
container.style.backgroundColor = backgroundColor || '';
container.style.color = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_DEBUGGING_FOREGROUND, STATUS_BAR_FOREGROUND)) || '';
// Border Color
const borderColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_DEBUGGING_BORDER, STATUS_BAR_BORDER)) || this.getColor(contrastBorder);
if (borderColor) {
container.classList.add('status-border-top');
container.style.setProperty('--status-border-top-color', borderColor.toString());
} else {
container.classList.remove('status-border-top');
container.style.removeProperty('--status-border-top-color');
}
// Notification Beak
if (!this.styleElement) {
this.styleElement = createStyleSheet(container);
}
this.styleElement.textContent = `.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor} !important; }`;
}
private getColorKey(noFolderColor: string, debuggingColor: string, normalColor: string): string {
// Not debugging
if (!isStatusbarInDebugMode(this.debugService.state, this.debugService.getViewModel().focusedSession)) {
if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) {
return normalColor;
}
return noFolderColor;
}
// Debugging
return debuggingColor;
dispose(): void {
this.disposable?.dispose();
this.disposables.dispose();
}
}
@@ -10,6 +10,7 @@ import { Event } from 'vs/base/common/event';
import { Command } from 'vs/editor/common/languages';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IStatusbarEntryLocation } from 'vs/workbench/browser/parts/statusbar/statusbarModel';
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
export const IStatusbarService = createDecorator<IStatusbarService>('statusbarService');
@@ -23,6 +24,13 @@ export const ShowTooltipCommand: Command = {
title: ''
};
export interface IStatusbarStyleOverride {
readonly priority: number; // lower has higher priority
readonly foreground?: ColorIdentifier;
readonly background?: ColorIdentifier;
readonly border?: ColorIdentifier;
}
/**
* A declarative way of describing a status bar entry
*/
@@ -145,6 +153,11 @@ export interface IStatusbarService {
* Returns true if a status bar entry is focused.
*/
isEntryFocused(): boolean;
/**
* Temporarily override statusbar style.
*/
overrideStyle(style: IStatusbarStyleOverride): IDisposable;
}
export interface IStatusbarEntryAccessor extends IDisposable {