diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index adfed271d0e..cee9d488cf6 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -507,7 +507,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { }; this.modeElement = this.updateElement(this.modeElement, props, 'status.editor.mode', nls.localize('status.editor.mode', "Editor Language"), StatusbarAlignment.RIGHT, 100.1); - } private updateMetadataElement(text: string | undefined): void { @@ -526,7 +525,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { }; this.metadataElement = this.updateElement(this.metadataElement, props, 'status.editor.info', nls.localize('status.editor.info', "File Information"), StatusbarAlignment.RIGHT, 100); - } private updateElement(element: IStatusbarEntryAccessor | null, props: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor | null { diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 5d5b31d2754..940467dab9b 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -81,16 +81,15 @@ height: 100%; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > span { - height: 100%; -} - -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > span, .monaco-workbench .part.statusbar > .items-container > .statusbar-entry > a { padding: 0 5px 0 5px; white-space: pre; /* gives some degree of styling */ } +.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > a.disabled { + pointer-events: none; +} + .monaco-workbench .part.statusbar > .items-container > .statusbar-entry span.octicon { text-align: center; font-size: 14px; diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index ef33b5cb254..654c846e5b7 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -24,7 +24,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { isThemeColor } from 'vs/editor/common/editorCommon'; import { Color } from 'vs/base/common/color'; -import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass, EventType, hide, show, removeClasses } from 'vs/base/browser/dom'; +import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, removeClass, EventType, hide, show, removeClasses } from 'vs/base/browser/dom'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -409,15 +409,6 @@ export class StatusbarPart extends Part implements IStatusbarService { return { update: entry => { - - // Update beak - if (entry.showBeak) { - addClass(itemContainer, 'has-beak'); - } else { - removeClass(itemContainer, 'has-beak'); - } - - // Update entry item.update(entry); }, dispose: () => { @@ -640,7 +631,15 @@ export class StatusbarPart extends Part implements IStatusbarService { } class StatusbarEntryItem extends Disposable { - private entryDisposables: IDisposable[] = []; + private entry: IStatusbarEntry; + + private labelContainer: HTMLElement; + private label: OcticonLabel; + + private foregroundListener: IDisposable | undefined; + private backgroundListener: IDisposable | undefined; + + private commandListener: IDisposable | undefined; constructor( private container: HTMLElement, @@ -653,61 +652,84 @@ class StatusbarEntryItem extends Disposable { ) { super(); - this.render(entry); + this.create(); + this.update(entry); + } + + private create(): void { + + // Label Container + this.labelContainer = document.createElement('a'); + + // Label + this.label = new OcticonLabel(this.labelContainer); + + // Add to parent + this.container.appendChild(this.labelContainer); } update(entry: IStatusbarEntry): void { - clearNode(this.container); - this.entryDisposables = dispose(this.entryDisposables); - this.render(entry); - } + // Update: Text + if (!this.entry || entry.text !== this.entry.text) { + this.label.text = entry.text; - private render(entry: IStatusbarEntry): void { - - // Text Container - let textContainer: HTMLElement; - if (entry.command) { - textContainer = document.createElement('a'); - - this.entryDisposables.push((addDisposableListener(textContainer, 'click', () => this.executeCommand(entry.command!, entry.arguments)))); - } else { - textContainer = document.createElement('span'); - } - - // Label - new OcticonLabel(textContainer).text = entry.text; - - // Tooltip - if (entry.tooltip) { - textContainer.title = entry.tooltip; - } - - // Color (only applies to text container) - this.applyColor(textContainer, entry.color); - - // Background Color (applies to parent element to fully fill container) - if (entry.backgroundColor) { - this.applyColor(this.container, entry.backgroundColor, true); - addClass(this.container, 'has-background-color'); - } - - this.container.appendChild(textContainer); - } - - private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void { - if (color) { - if (isThemeColor(color)) { - const colorId = color.id; - color = (this.themeService.getTheme().getColor(colorId) || Color.transparent).toString(); - this.entryDisposables.push(((this.themeService.onThemeChange(theme => { - const colorValue = (theme.getColor(colorId) || Color.transparent).toString(); - isBackground ? container.style.backgroundColor = colorValue : container.style.color = colorValue; - })))); + if (entry.text) { + show(this.labelContainer); + } else { + hide(this.labelContainer); } - - isBackground ? container.style.backgroundColor = color : container.style.color = color; } + + // Update: Tooltip + if (!this.entry || entry.tooltip !== this.entry.tooltip) { + if (entry.tooltip) { + this.labelContainer.title = entry.tooltip; + } else { + delete this.labelContainer.title; + } + } + + // Update: Command + if (!this.entry || entry.command !== this.entry.command) { + dispose(this.commandListener); + this.commandListener = undefined; + + if (entry.command) { + this.commandListener = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(entry.command!, entry.arguments)); + + removeClass(this.labelContainer, 'disabled'); + } else { + addClass(this.labelContainer, 'disabled'); + } + } + + // Update: Beak + if (!this.entry || entry.showBeak !== this.entry.showBeak) { + if (entry.showBeak) { + addClass(this.container, 'has-beak'); + } else { + removeClass(this.container, 'has-beak'); + } + } + + // Update: Foreground + if (!this.entry || entry.color !== this.entry.color) { + this.applyColor(this.labelContainer, entry.color); + } + + // Update: Backgroud + if (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) { + if (entry.backgroundColor) { + this.applyColor(this.container, entry.backgroundColor, true); + addClass(this.container, 'has-background-color'); + } else { + removeClass(this.container, 'has-background-color'); + } + } + + // Remember for next round + this.entry = entry; } private async executeCommand(id: string, args?: unknown[]): Promise { @@ -733,10 +755,54 @@ class StatusbarEntryItem extends Disposable { } } + private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void { + let colorResult: string | null = null; + + if (isBackground) { + dispose(this.backgroundListener); + this.backgroundListener = undefined; + } else { + dispose(this.foregroundListener); + this.foregroundListener = undefined; + } + + if (color) { + if (isThemeColor(color)) { + colorResult = (this.themeService.getTheme().getColor(color.id) || Color.transparent).toString(); + + const listener = this.themeService.onThemeChange(theme => { + const colorValue = (theme.getColor(color.id) || Color.transparent).toString(); + + if (isBackground) { + container.style.backgroundColor = colorValue; + } else { + container.style.color = colorValue; + } + }); + + if (isBackground) { + this.backgroundListener = listener; + } else { + this.foregroundListener = listener; + } + } else { + colorResult = color; + } + } + + if (isBackground) { + container.style.backgroundColor = colorResult; + } else { + container.style.color = colorResult; + } + } + dispose(): void { super.dispose(); - this.entryDisposables = dispose(this.entryDisposables); + dispose(this.foregroundListener); + dispose(this.backgroundListener); + dispose(this.commandListener); } } diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index bca49d5ab4d..b2926f0be76 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; import { localize } from 'vs/nls'; import { registerColor, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -111,10 +111,3 @@ export function isStatusbarInDebugMode(debugService: IDebugService): boolean { return true; } - -registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { - const statusBarItemDebuggingForeground = theme.getColor(STATUS_BAR_DEBUGGING_FOREGROUND); - if (statusBarItemDebuggingForeground) { - collector.addRule(`.monaco-workbench .part.statusbar.debugging > .items-container > .statusbar-item .mask-icon { background-color: ${statusBarItemDebuggingForeground} !important; }`); - } -}); diff --git a/test/smoke/src/areas/statusbar/statusbar.ts b/test/smoke/src/areas/statusbar/statusbar.ts index da1cf344445..c9bfa19bc5c 100644 --- a/test/smoke/src/areas/statusbar/statusbar.ts +++ b/test/smoke/src/areas/statusbar/statusbar.ts @@ -50,15 +50,15 @@ export class StatusBar { case StatusBarElement.PROBLEMS_STATUS: return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-error`; case StatusBarElement.SELECTION_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-selection`; + return `${this.mainSelector} ${this.rightSelector} a[title="Go to Line"]`; case StatusBarElement.INDENTATION_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-indentation`; + return `${this.mainSelector} ${this.rightSelector} a[title="Select Indentation"]`; case StatusBarElement.ENCODING_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-encoding`; + return `${this.mainSelector} ${this.rightSelector} a[title="Select Encoding"]`; case StatusBarElement.EOL_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-eol`; + return `${this.mainSelector} ${this.rightSelector} a[title="Select End of Line Sequence"]`; case StatusBarElement.LANGUAGE_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-mode`; + return `${this.mainSelector} ${this.rightSelector} a[title="Select Language Mode"]`; case StatusBarElement.FEEDBACK_ICON: return `${this.mainSelector} ${this.rightSelector} .monaco-dropdown.send-feedback`; default: