diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 0a48466b628ea23365f31edb8136afd5e39c9c4d..cbe0e8da9681296b1543999dc03f84e3b99990e4 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -12,7 +12,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, $ } from 'vs/base/browser/builder'; import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { Action } from 'vs/base/common/actions'; -import { BaseActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem, Separator, IBaseActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { IActivityBarService, ProgressBadge, TextBadge, NumberBadge, IconBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; import Event, { Emitter } from 'vs/base/common/event'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -23,9 +23,9 @@ import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { dispose } from 'vs/base/common/lifecycle'; import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IThemeService, ITheme } from "vs/platform/theme/common/themeService"; +import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from "vs/platform/theme/common/themeService"; import { ACTIVITY_BADGE_FOREGROUND, ACTIVITY_BADGE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from "vs/workbench/common/theme"; -import { highContrastBorder } from "vs/platform/theme/common/colorRegistry"; +import { highContrastBorder, highContrastOutline, focus } from "vs/platform/theme/common/colorRegistry"; export class ActivityAction extends Action { private badge: IBadge; @@ -102,13 +102,33 @@ export class ViewletActivityAction extends ActivityAction { } } -export class ActivityActionItem extends BaseActionItem { +export abstract class ThemableActivityActionItem extends BaseActionItem { + + constructor( + action: ActivityAction, + options: IBaseActionItemOptions, + @IThemeService protected themeService: IThemeService + ) { + super(null, action, options); + + this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); + } + + private onThemeChange(theme: ITheme): void { + this.updateStyles(); + } + + protected abstract updateStyles(): void; +} + +export class ActivityActionItem extends ThemableActivityActionItem { private static manageExtensionAction: ManageExtensionAction; private static toggleViewletPinnedAction: ToggleViewletPinnedAction; private static draggedViewlet: ViewletDescriptor; - private $e: Builder; + private $container: Builder; + private $label: Builder; private name: string; private _keybinding: string; private cssClass: string; @@ -123,9 +143,9 @@ export class ActivityActionItem extends BaseActionItem { @IActivityBarService private activityBarService: IActivityBarService, @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService + @IThemeService themeService: IThemeService ) { - super(null, action, { draggable: true }); + super(action, { draggable: true }, themeService); this.cssClass = action.class; this.name = viewlet.name; @@ -140,21 +160,16 @@ export class ActivityActionItem extends BaseActionItem { } action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose); - this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); } - private onThemeChange(theme: ITheme): void { - this.updateStyles(); - } - - private updateStyles(): void { + protected updateStyles(): void { const theme = this.themeService.getTheme(); // Label - if (this.$e) { + if (this.$label) { const background = theme.getColor(ACTIVITY_BAR_FOREGROUND); - this.$e.style('background-color', background ? background.toString() : null); + this.$label.style('background-color', background ? background.toString() : null); } // Badge @@ -184,53 +199,33 @@ export class ActivityActionItem extends BaseActionItem { public render(container: HTMLElement): void { super.render(container); - this.$e = $('a.action-label').attr({ - tabIndex: '0', - role: 'button' - }).appendTo(this.builder); + this.$container = $(container).attr({ + tabIndex: '0' + }); // Try hard to prevent keyboard only focus feedback when using mouse - this.$e.on(DOM.EventType.MOUSE_DOWN, () => { - this.$e.addClass('clicked'); + this.$container.on(DOM.EventType.MOUSE_DOWN, () => { + this.$container.addClass('clicked'); }); - this.$e.on(DOM.EventType.MOUSE_UP, () => { + this.$container.on(DOM.EventType.MOUSE_UP, () => { if (this.mouseUpTimeout) { clearTimeout(this.mouseUpTimeout); } this.mouseUpTimeout = setTimeout(() => { - this.$e.removeClass('clicked'); + this.$container.removeClass('clicked'); }, 800); // delayed to prevent focus feedback from showing on mouse up }); - $(container).on('contextmenu', e => { + this.$container.on('contextmenu', e => { DOM.EventHelper.stop(e, true); this.showContextMenu(container); }); - if (this.cssClass) { - this.$e.addClass(this.cssClass); - } - - this.$badge = this.builder.div({ 'class': 'badge' }, (badge: Builder) => { - this.$badgeContent = badge.div({ 'class': 'badge-content' }); - }); - - this.$badge.hide(); - - this.keybinding = this._keybinding; // force update - - // Activate on drag over to reveal targets - [this.$badge, this.$e].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { - if (!ActivityActionItem.getDraggedViewlet() && !this.getAction().checked) { - this.getAction().run(); - } - })); - // Allow to drag - $(container).on(DOM.EventType.DRAG_START, (e: DragEvent) => { + this.$container.on(DOM.EventType.DRAG_START, (e: DragEvent) => { e.dataTransfer.effectAllowed = 'move'; this.setDraggedViewlet(this.viewlet); @@ -242,7 +237,7 @@ export class ActivityActionItem extends BaseActionItem { // Drag enter let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 - $(container).on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => { + this.$container.on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => { const draggedViewlet = ActivityActionItem.getDraggedViewlet(); if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) { counter++; @@ -251,7 +246,7 @@ export class ActivityActionItem extends BaseActionItem { }); // Drag leave - $(container).on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => { + this.$container.on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => { const draggedViewlet = ActivityActionItem.getDraggedViewlet(); if (draggedViewlet) { counter--; @@ -262,7 +257,7 @@ export class ActivityActionItem extends BaseActionItem { }); // Drag end - $(container).on(DOM.EventType.DRAG_END, (e: DragEvent) => { + this.$container.on(DOM.EventType.DRAG_END, (e: DragEvent) => { const draggedViewlet = ActivityActionItem.getDraggedViewlet(); if (draggedViewlet) { counter = 0; @@ -273,7 +268,7 @@ export class ActivityActionItem extends BaseActionItem { }); // Drop - $(container).on(DOM.EventType.DROP, (e: DragEvent) => { + this.$container.on(DOM.EventType.DROP, (e: DragEvent) => { DOM.EventHelper.stop(e, true); const draggedViewlet = ActivityActionItem.getDraggedViewlet(); @@ -285,6 +280,29 @@ export class ActivityActionItem extends BaseActionItem { } }); + // Label + this.$label = $('a.action-label').appendTo(this.builder); + if (this.cssClass) { + this.$label.addClass(this.cssClass); + } + + // Badge + this.$badge = this.builder.div({ 'class': 'badge' }, (badge: Builder) => { + this.$badgeContent = badge.div({ 'class': 'badge-content' }); + }); + + this.$badge.hide(); + + // Keybinding + this.keybinding = this._keybinding; // force update + + // Activate on drag over to reveal targets + [this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { + if (!ActivityActionItem.getDraggedViewlet() && !this.getAction().checked) { + this.getAction().run(); + } + })); + this.updateStyles(); } @@ -329,7 +347,7 @@ export class ActivityActionItem extends BaseActionItem { } public focus(): void { - this.$e.domFocus(); + this.$container.domFocus(); } public setBadge(badge: IBadge): void { @@ -339,7 +357,7 @@ export class ActivityActionItem extends BaseActionItem { public set keybinding(keybinding: string) { this._keybinding = keybinding; - if (!this.$e) { + if (!this.$label) { return; } @@ -350,7 +368,7 @@ export class ActivityActionItem extends BaseActionItem { title = this.name; } - this.$e.title(title); + this.$label.title(title); this.$badge.title(title); } @@ -384,7 +402,7 @@ export class ActivityActionItem extends BaseActionItem { this.$badge.show(); } - this.$e.attr('aria-label', `${this.name} - ${badge.getDescription()}`); + this.$label.attr('aria-label', `${this.name} - ${badge.getDescription()}`); } } @@ -399,9 +417,9 @@ export class ActivityActionItem extends BaseActionItem { protected _updateChecked(): void { if (this.getAction().checked) { - this.$e.addClass('active'); + this.$container.addClass('active'); } else { - this.$e.removeClass('active'); + this.$container.removeClass('active'); } } @@ -430,7 +448,7 @@ export class ActivityActionItem extends BaseActionItem { } this.$badge.destroy(); - this.$e.destroy(); + this.$label.destroy(); } } @@ -449,8 +467,8 @@ export class ViewletOverflowActivityAction extends ActivityAction { } } -export class ViewletOverflowActivityActionItem extends BaseActionItem { - private $e: Builder; +export class ViewletOverflowActivityActionItem extends ThemableActivityActionItem { + private $label: Builder; private name: string; private cssClass: string; private actions: OpenViewletAction[]; @@ -463,22 +481,36 @@ export class ViewletOverflowActivityActionItem extends BaseActionItem { @IViewletService private viewletService: IViewletService, @IKeybindingService private keybindingService: IKeybindingService, @IContextMenuService private contextMenuService: IContextMenuService, + @IThemeService themeService: IThemeService ) { - super(null, action); + super(action, null, themeService); this.cssClass = action.class; this.name = action.label; } + protected updateStyles(): void { + const theme = this.themeService.getTheme(); + + // Label + if (this.$label) { + const background = theme.getColor(ACTIVITY_BAR_FOREGROUND); + + this.$label.style('background-color', background ? background.toString() : null); + } + } + public render(container: HTMLElement): void { super.render(container); - this.$e = $('a.action-label').attr({ + this.$label = $('a.action-label').attr({ tabIndex: '0', role: 'button', title: this.name, class: this.cssClass }).appendTo(this.builder); + + this.updateStyles(); } public showMenu(): void { @@ -590,4 +622,66 @@ export class ToggleViewletPinnedAction extends Action { return TPromise.as(true); } -} \ No newline at end of file +} + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + + // Styling with Outline color (e.g. high contrast theme) + const outline = theme.getColor(highContrastOutline); + if (outline) { + collector.addRule(` + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:before { + content: ""; + position: absolute; + top: 9px; + left: 9px; + height: 32px; + width: 32px; + opacity: 0.6; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar.global .action-item.active:before { + border: none; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:before, + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:hover:before { + outline: 1px solid; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover:before { + outline: 1px dashed; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:before, + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover:before { + opacity: 1; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before { + border-left-color: ${outline}; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:before, + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:hover:before, + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover:before { + outline-color: ${outline}; + } + `); + } + + // Styling without outline color + else { + const focusBorder = theme.getColor(focus); + + collector.addRule(` + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item { + opacity: 0.6; + } + + .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before { + border-left-color: ${focusBorder}; + } + `); + } +}); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 19f8ef1767e8430d086671649e3811bd5dc903ca..ddd13ae02d7e7ba83f8ff3ce451830945727f257 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -30,9 +30,9 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility'; import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; -import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { highContrastBorder, highContrastOutline, focus } from 'vs/platform/theme/common/colorRegistry'; +import { highContrastBorder } from 'vs/platform/theme/common/colorRegistry'; interface IViewletActivity { badge: IBadge; @@ -512,68 +512,4 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Pass to super super.shutdown(); } -} - -registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { - - // Styling with Outline color (e.g. high contrast theme) - const outline = theme.getColor(highContrastOutline); - if (outline) { - collector.addRule(` - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-label:before { - content: ""; - position: absolute; - top: 9px; - left: 9px; - height: 32px; - width: 32px; - opacity: 0.6; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar.global .action-item .action-label.active:before { - border: none; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active:before, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active:hover:before { - outline: 1px solid; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label:hover:before { - outline: 1px dashed; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-label, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-label.active, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active:before, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover .action-label:before { - opacity: 1; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label:focus:before { - border-left-color: ${outline}; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active:before, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active:hover:before, - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label:hover:before { - outline-color: ${outline}; - } - `); - } - - // Styling without outline color - else { - const focusBorder = theme.getColor(focus); - - collector.addRule(` - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-label { - opacity: 0.6; - } - - .monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label:focus:before { - border-left-color: ${focusBorder}; - } - `); - } -}); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 504d6b7cbdb8622c1b57fc75a1ea3ec526d6f1e0..e4e2818ad03feec95f07967a758c0ab31c57acdc 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -17,12 +17,10 @@ margin-right: 0; padding: 0 0 0 50px; box-sizing: border-box; - background-position: 9px center; - background-repeat: no-repeat; font-size: 15px; } -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label:focus:before { +.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before { content: ""; position: absolute; top: 9px; @@ -31,25 +29,20 @@ border-left: 2px solid; } -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.clicked:focus:before { +.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.clicked:focus:before { border-left: none !important; /* no focus feedback when using mouse */ } -.monaco-workbench > .activitybar.left > .content .monaco-action-bar .action-item .action-label:focus:before { +.monaco-workbench > .activitybar.left > .content .monaco-action-bar .action-item:focus:before { left: 1px; } -.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-item .action-label:focus:before { +.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-item:focus:before { right: 1px; } .monaco-workbench > .activitybar > .content .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-global.svg'); -} - -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-label > .label { - flex: 1 1 auto; - overflow: hidden; + -webkit-mask: url('ellipsis-global.svg') no-repeat 50% 50%; } .monaco-workbench > .activitybar > .content .monaco-action-bar .badge { @@ -74,8 +67,8 @@ text-align: center; } -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item .action-label.active, -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover .action-label { +.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active, +.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover { opacity: 1; } @@ -87,15 +80,6 @@ background-position: calc(100% - 9px) center; } -.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-label .label { - padding-left: 1em; -} - -.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-label > .keybinding { - text-align: right; - padding: 0 0 0 2em; -} - .monaco-workbench > .activitybar.right > .content .monaco-action-bar .badge { left: auto; right: 0;