提交 95c23d21 编写于 作者: J Joao Moreno

wip: ViewletActivityAction in activity bar

上级 41de158b
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/platform';
import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
export interface IActivity {
id: string;
name: string;
cssClass: string;
}
export const Extensions = {
Activities: 'workbench.contributions.activities'
};
export interface IActivityRegistry {
registerActivity(descriptor: IConstructorSignature0<IActivity>): void;
getActivities(): IConstructorSignature0<IActivity>[];
}
export class ActivityRegistry implements IActivityRegistry {
private activityDescriptors = new Set<IConstructorSignature0<IActivity>>();
registerActivity(descriptor: IConstructorSignature0<IActivity>): void {
this.activityDescriptors.add(descriptor);
}
getActivities(): IConstructorSignature0<IActivity>[] {
const result: IConstructorSignature0<IActivity>[] = [];
this.activityDescriptors.forEach(d => result.push(d));
return result;
}
}
Registry.add(Extensions.Activities, new ActivityRegistry());
\ No newline at end of file
......@@ -20,6 +20,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IActivity } from 'vs/workbench/browser/activity';
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';
......@@ -31,8 +32,12 @@ export class ActivityAction extends Action {
private badge: IBadge;
private _onDidChangeBadge = new Emitter<this>();
constructor(id: string, name: string, clazz: string) {
super(id, name, clazz);
get activity(): IActivity {
return this._activity;
}
constructor(private _activity: IActivity) {
super(_activity.id, _activity.name, _activity.cssClass);
this.badge = null;
}
......@@ -74,7 +79,7 @@ export class ViewletActivityAction extends ActivityAction {
@IViewletService private viewletService: IViewletService,
@IPartService private partService: IPartService
) {
super(viewlet.id, viewlet.name, viewlet.cssClass);
super(viewlet);
}
public run(event): TPromise<any> {
......@@ -102,7 +107,15 @@ export class ViewletActivityAction extends ActivityAction {
}
}
export abstract class ThemableActivityActionItem extends BaseActionItem {
export class ActivityActionItem extends BaseActionItem {
protected $label: Builder;
protected $badge: Builder;
private $badgeContent: Builder;
protected get activity(): IActivity {
return (this._action as ActivityAction).activity;
}
constructor(
action: ActivityAction,
......@@ -114,31 +127,114 @@ export abstract class ThemableActivityActionItem extends BaseActionItem {
this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose);
}
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);
}
// Badge
if (this.$badgeContent) {
const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND);
const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND);
const contrastBorderColor = theme.getColor(contrastBorder);
this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null);
this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null);
this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null);
this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null);
this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null);
}
}
public render(container: HTMLElement): void {
super.render(container);
// Label
this.$label = $('a.action-label').appendTo(this.builder);
if (this.activity.cssClass) {
this.$label.addClass(this.activity.cssClass);
}
this.$badge = this.builder.div({ 'class': 'badge' }, (badge: Builder) => {
this.$badgeContent = badge.div({ 'class': 'badge-content' });
});
this.$badge.hide();
this.updateStyles();
}
private onThemeChange(theme: ITheme): void {
this.updateStyles();
}
protected abstract updateStyles(): void;
public setBadge(badge: IBadge): void {
this.updateBadge(badge);
}
protected updateBadge(badge: IBadge): void {
this.$badgeContent.empty();
this.$badge.hide();
if (badge) {
// Number
if (badge instanceof NumberBadge) {
if (badge.number) {
this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString());
this.$badge.show();
}
}
// Text
else if (badge instanceof TextBadge) {
this.$badgeContent.text(badge.text);
this.$badge.show();
}
// Text
else if (badge instanceof IconBadge) {
this.$badge.show();
}
// Progress
else if (badge instanceof ProgressBadge) {
this.$badge.show();
}
this.$label.attr('aria-label', `${this.activity.name} - ${badge.getDescription()}`);
}
}
public dispose(): void {
super.dispose();
this.$badge.destroy();
}
}
export class ActivityActionItem extends ThemableActivityActionItem {
export class ViewletActionItem extends ActivityActionItem {
private static manageExtensionAction: ManageExtensionAction;
private static toggleViewletPinnedAction: ToggleViewletPinnedAction;
private static draggedViewlet: ViewletDescriptor;
private $container: Builder;
private $label: Builder;
private name: string;
private _keybinding: string;
private cssClass: string;
private $badge: Builder;
private $badgeContent: Builder;
private mouseUpTimeout: number;
private get viewlet(): ViewletDescriptor {
return this.action.activity as ViewletDescriptor;
}
constructor(
action: ActivityAction,
private viewlet: ViewletDescriptor,
private action: ViewletActivityAction,
@IContextMenuService private contextMenuService: IContextMenuService,
@IActivityBarService private activityBarService: IActivityBarService,
@IKeybindingService private keybindingService: IKeybindingService,
......@@ -148,45 +244,19 @@ export class ActivityActionItem extends ThemableActivityActionItem {
super(action, { draggable: true }, themeService);
this.cssClass = action.class;
this.name = viewlet.name;
this._keybinding = this.getKeybindingLabel(viewlet.id);
this._keybinding = this.getKeybindingLabel(this.viewlet.id);
if (!ActivityActionItem.manageExtensionAction) {
ActivityActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
if (!ViewletActionItem.manageExtensionAction) {
ViewletActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
}
if (!ActivityActionItem.toggleViewletPinnedAction) {
ActivityActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0);
if (!ViewletActionItem.toggleViewletPinnedAction) {
ViewletActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0);
}
action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose);
}
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);
}
// Badge
if (this.$badgeContent) {
const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND);
const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND);
const contrastBorderColor = theme.getColor(contrastBorder);
this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null);
this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null);
this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null);
this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null);
this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null);
}
}
private getKeybindingLabel(id: string): string {
const kb = this.keybindingService.lookupKeybinding(id);
if (kb) {
......@@ -240,7 +310,7 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag enter
let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470
this.$container.on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) {
counter++;
this.updateFromDragging(container, true);
......@@ -249,7 +319,7 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag leave
this.$container.on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
counter--;
if (counter === 0) {
......@@ -260,12 +330,12 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag end
this.$container.on(DOM.EventType.DRAG_END, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
counter = 0;
this.updateFromDragging(container, false);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
}
});
......@@ -273,34 +343,21 @@ export class ActivityActionItem extends ThemableActivityActionItem {
this.$container.on(DOM.EventType.DROP, (e: DragEvent) => {
DOM.EventHelper.stop(e, true);
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) {
this.updateFromDragging(container, false);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
this.activityBarService.move(draggedViewlet.id, this.viewlet.id);
}
});
// 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) {
if (!ViewletActionItem.getDraggedViewlet() && !this.getAction().checked) {
this.getAction().run();
}
}));
......@@ -316,29 +373,29 @@ export class ActivityActionItem extends ThemableActivityActionItem {
}
public static getDraggedViewlet(): ViewletDescriptor {
return ActivityActionItem.draggedViewlet;
return ViewletActionItem.draggedViewlet;
}
private setDraggedViewlet(viewlet: ViewletDescriptor): void {
ActivityActionItem.draggedViewlet = viewlet;
ViewletActionItem.draggedViewlet = viewlet;
}
public static clearDraggedViewlet(): void {
ActivityActionItem.draggedViewlet = void 0;
ViewletActionItem.draggedViewlet = void 0;
}
private showContextMenu(container: HTMLElement): void {
const actions: Action[] = [ActivityActionItem.toggleViewletPinnedAction];
const actions: Action[] = [ViewletActionItem.toggleViewletPinnedAction];
if (this.viewlet.extensionId) {
actions.push(new Separator());
actions.push(ActivityActionItem.manageExtensionAction);
actions.push(ViewletActionItem.manageExtensionAction);
}
const isPinned = this.activityBarService.isPinned(this.viewlet.id);
if (isPinned) {
ActivityActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Remove from Activity Bar");
ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Remove from Activity Bar");
} else {
ActivityActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar");
ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar");
}
this.contextMenuService.showContextMenu({
......@@ -352,10 +409,6 @@ export class ActivityActionItem extends ThemableActivityActionItem {
this.$container.domFocus();
}
public setBadge(badge: IBadge): void {
this.updateBadge(badge);
}
public set keybinding(keybinding: string) {
this._keybinding = keybinding;
......@@ -365,49 +418,15 @@ export class ActivityActionItem extends ThemableActivityActionItem {
let title: string;
if (keybinding) {
title = nls.localize('titleKeybinding', "{0} ({1})", this.name, keybinding);
title = nls.localize('titleKeybinding', "{0} ({1})", this.activity.name, keybinding);
} else {
title = this.name;
title = this.activity.name;
}
this.$label.title(title);
this.$badge.title(title);
}
private updateBadge(badge: IBadge): void {
this.$badgeContent.empty();
this.$badge.hide();
if (badge) {
// Number
if (badge instanceof NumberBadge) {
if (badge.number) {
this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString());
this.$badge.show();
}
}
// Text
else if (badge instanceof TextBadge) {
this.$badgeContent.text(badge.text);
this.$badge.show();
}
// Text
else if (badge instanceof IconBadge) {
this.$badge.show();
}
// Progress
else if (badge instanceof ProgressBadge) {
this.$badge.show();
}
this.$label.attr('aria-label', `${this.name} - ${badge.getDescription()}`);
}
}
protected _updateClass(): void {
if (this.cssClass) {
this.$badge.removeClass(this.cssClass);
......@@ -443,13 +462,12 @@ export class ActivityActionItem extends ThemableActivityActionItem {
public dispose(): void {
super.dispose();
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
if (this.mouseUpTimeout) {
clearTimeout(this.mouseUpTimeout);
}
this.$badge.destroy();
this.$label.destroy();
}
}
......@@ -459,7 +477,11 @@ export class ViewletOverflowActivityAction extends ActivityAction {
constructor(
private showMenu: () => void
) {
super('activitybar.additionalViewlets.action', nls.localize('additionalViews', "Additional Views"), 'toggle-more');
super({
id: 'activitybar.additionalViewlets.action',
name: nls.localize('additionalViews', "Additional Views"),
cssClass: 'toggle-more'
});
}
public run(event): TPromise<any> {
......@@ -469,8 +491,8 @@ export class ViewletOverflowActivityAction extends ActivityAction {
}
}
export class ViewletOverflowActivityActionItem extends ThemableActivityActionItem {
private $label: Builder;
export class ViewletOverflowActivityActionItem extends ActivityActionItem {
private name: string;
private cssClass: string;
private actions: OpenViewletAction[];
......
......@@ -15,9 +15,11 @@ import { Builder, $, Dimension } from 'vs/base/browser/builder';
import { Action } from 'vs/base/common/actions';
import { ActionsOrientation, ActionBar, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IActivity, Extensions as ActivityExtensions, IActivityRegistry } from 'vs/workbench/browser/activity';
import { Registry } from 'vs/platform/platform';
import { Part } from 'vs/workbench/browser/part';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, ActivityActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, ViewletActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService';
import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
......@@ -38,6 +40,21 @@ interface IViewletActivity {
clazz: string;
}
class GlobalActivityAction extends ActivityAction {
constructor(activity: IActivity) {
super(activity);
}
}
class GlobalActivityActionItem extends ViewletActionItem {
onClick(event: Event): void {
DOM.EventHelper.stop(event, true);
// fire up native menu around this.builder.getHTMLElement()
}
}
export class ActivitybarPart extends Part implements IActivityBarService {
private static readonly ACTIVITY_ACTION_HEIGHT = 50;
......@@ -48,6 +65,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private dimension: Dimension;
private viewletSwitcherBar: ActionBar;
private activityActionBar: ActionBar;
private viewletOverflowAction: ViewletOverflowActivityAction;
private viewletOverflowActionItem: ViewletOverflowActivityActionItem;
......@@ -180,6 +198,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Top Actionbar with action items for each viewlet action
this.createViewletSwitcher($result.clone());
// Top Actionbar with action items for each viewlet action
this.createActivityActionBar($result.getHTMLElement());
// Contextmenu for viewlets
$(parent).on('contextmenu', (e: MouseEvent) => {
DOM.EventHelper.stop(e, true);
......@@ -189,11 +210,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Allow to drop at the end to move viewlet to the end
$(parent).on(DOM.EventType.DROP, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
DOM.EventHelper.stop(e, true);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
const targetId = this.pinnedViewlets[this.pinnedViewlets.length - 1];
if (targetId !== draggedViewlet.id) {
......@@ -252,6 +273,29 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.extensionService.onReady().then(() => this.updateViewletSwitcher());
}
private createActivityActionBar(container: HTMLElement): void {
const activityRegistry = Registry.as<IActivityRegistry>(ActivityExtensions.Activities);
const descriptors = activityRegistry.getActivities();
const actions = descriptors
.map(d => this.instantiationService.createInstance(d))
.map(a => new GlobalActivityAction(a));
this.activityActionBar = new ActionBar(container, {
actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a),
orientation: ActionsOrientation.VERTICAL,
ariaLabel: nls.localize('globalActions', "Global Actions"),
animated: false
});
actions.forEach(a => this.activityActionBar.push(a));
this.updateGlobalSwitcher();
}
private updateGlobalSwitcher(): void {
}
private updateViewletSwitcher() {
let viewletsToShow = this.getPinnedViewlets();
......@@ -371,7 +415,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private toAction(viewlet: ViewletDescriptor): ActivityAction {
const action = this.instantiationService.createInstance(ViewletActivityAction, viewlet);
this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ActivityActionItem, action, viewlet);
this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ViewletActionItem, action);
this.viewletIdToActions[viewlet.id] = action;
return action;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册