panelPart.ts 9.6 KB
Newer Older
I
isidor 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

B
Benjamin Pasero 已提交
6
import 'vs/css!./media/panelpart';
I
isidor 已提交
7
import nls = require('vs/nls');
J
Johannes Rieken 已提交
8
import { TPromise } from 'vs/base/common/winjs.base';
9
import { IAction } from 'vs/base/common/actions';
10
import Event from 'vs/base/common/event';
11
import { Builder, $ } from 'vs/base/browser/builder';
12
import { Registry } from 'vs/platform/registry/common/platform';
13
import { Scope } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
14
import { IPanel } from 'vs/workbench/common/panel';
15
import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/compositePart';
16 17
import { Panel, PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
18
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
J
Johannes Rieken 已提交
19 20 21 22 23 24
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IMessageService } from 'vs/platform/message/common/message';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
25
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
I
isidor 已提交
26
import { ClosePanelAction, OpenPanelAction, ToggleMaximizedPanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
27
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
28
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER } from 'vs/workbench/common/theme';
29
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry';
I
isidor 已提交
30 31 32 33 34

export class PanelPart extends CompositePart<Panel> implements IPanelService {

	public static activePanelSettingsKey = 'workbench.panelpart.activepanelid';

35
	public _serviceBrand: any;
36

I
isidor 已提交
37
	private blockOpeningPanel: boolean;
38 39
	private panelSwitcherBar: ActionBar;

I
isidor 已提交
40
	private panelIdToActions: { [panelId: string]: OpenPanelAction; };
I
isidor 已提交
41 42

	constructor(
43 44 45 46 47 48
		id: string,
		@IMessageService messageService: IMessageService,
		@IStorageService storageService: IStorageService,
		@ITelemetryService telemetryService: ITelemetryService,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IPartService partService: IPartService,
49
		@IKeybindingService keybindingService: IKeybindingService,
50 51
		@IInstantiationService instantiationService: IInstantiationService,
		@IThemeService themeService: IThemeService
I
isidor 已提交
52
	) {
53 54 55 56 57 58 59
		super(
			messageService,
			storageService,
			telemetryService,
			contextMenuService,
			partService,
			keybindingService,
60
			instantiationService,
61
			themeService,
62
			Registry.as<PanelRegistry>(PanelExtensions.Panels),
63
			PanelPart.activePanelSettingsKey,
64
			Registry.as<PanelRegistry>(PanelExtensions.Panels).getDefaultPanelId(),
65 66 67
			'panel',
			'panel',
			Scope.PANEL,
68
			null,
69 70
			id,
			{ hasTitle: true }
71
		);
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

		this.panelIdToActions = Object.create(null);

		this.registerListeners();
	}

	private registerListeners(): void {

		// Activate panel action on opening of a panel
		this.toUnbind.push(this.onDidPanelOpen(panel => this.updatePanelActions(panel.getId(), true)));

		// Deactivate panel action on close
		this.toUnbind.push(this.onDidPanelClose(panel => this.updatePanelActions(panel.getId(), false)));
	}

	private updatePanelActions(id: string, didOpen: boolean): void {
		if (this.panelIdToActions[id]) {
			didOpen ? this.panelIdToActions[id].activate() : this.panelIdToActions[id].deactivate();
		}
I
isidor 已提交
91 92
	}

93
	public get onDidPanelOpen(): Event<IPanel> {
94
		return this._onDidCompositeOpen.event;
95 96 97
	}

	public get onDidPanelClose(): Event<IPanel> {
98
		return this._onDidCompositeClose.event;
99 100
	}

B
Benjamin Pasero 已提交
101
	protected updateStyles(): void {
102 103
		super.updateStyles();

B
Benjamin Pasero 已提交
104
		const container = this.getContainer();
105
		container.style('background-color', this.getColor(PANEL_BACKGROUND));
B
Benjamin Pasero 已提交
106 107

		const title = this.getTitleArea();
108
		title.style('border-top-color', this.getColor(PANEL_BORDER) || this.getColor(contrastBorder));
109 110
	}

I
isidor 已提交
111 112 113 114 115
	public openPanel(id: string, focus?: boolean): TPromise<Panel> {
		if (this.blockOpeningPanel) {
			return TPromise.as(null); // Workaround against a potential race condition
		}

116
		// First check if panel is hidden and show if so
117
		let promise = TPromise.as<any>(null);
118
		if (!this.partService.isVisible(Parts.PANEL_PART)) {
I
isidor 已提交
119 120
			try {
				this.blockOpeningPanel = true;
121
				promise = this.partService.setPanelHidden(false);
I
isidor 已提交
122 123 124 125 126
			} finally {
				this.blockOpeningPanel = false;
			}
		}

127
		return promise.then(() => this.openComposite(id, focus));
I
isidor 已提交
128 129
	}

130 131
	public getPanels(): IPanelIdentifier[] {
		return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels()
B
Benjamin Pasero 已提交
132
			.sort((v1, v2) => v1.order - v2.order);
133 134
	}

I
isidor 已提交
135
	protected getActions(): IAction[] {
I
isidor 已提交
136 137 138 139
		return [
			this.instantiationService.createInstance(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL),
			this.instantiationService.createInstance(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL)
		];
I
isidor 已提交
140 141
	}

I
isidor 已提交
142 143 144 145 146 147 148 149 150
	public getActivePanel(): IPanel {
		return this.getActiveComposite();
	}

	public getLastActivePanelId(): string {
		return this.getLastActiveCompositetId();
	}

	public hideActivePanel(): TPromise<void> {
151
		return this.hideActiveComposite().then(composite => void 0);
I
isidor 已提交
152
	}
I
isidor 已提交
153

154 155 156 157
	protected createTitleLabel(parent: Builder): ICompositeTitleLabel {
		let titleArea = $(parent).div({
			'class': ['panel-switcher-container']
		});
I
isidor 已提交
158

159 160 161 162 163 164
		// Show a panel switcher
		this.panelSwitcherBar = new ActionBar(titleArea, {
			orientation: ActionsOrientation.HORIZONTAL,
			ariaLabel: nls.localize('panelSwitcherBarAriaLabel', "Active Panel Switcher"),
			animated: false
		});
B
Benjamin Pasero 已提交
165
		this.toUnbind.push(this.panelSwitcherBar);
I
isidor 已提交
166

B
Benjamin Pasero 已提交
167
		this.fillPanelSwitcher();
I
isidor 已提交
168

169 170 171 172 173 174
		return {
			updateTitle: (id, title, keybinding) => {
				const action = this.panelIdToActions[id];
				if (action) {
					action.label = title;
				}
175 176
			},
			updateStyles: () => {
177
				// Handled via theming participant
178 179
			}
		};
I
isidor 已提交
180 181
	}

B
Benjamin Pasero 已提交
182
	private fillPanelSwitcher(): void {
183
		const panels = this.getPanels();
I
isidor 已提交
184

185
		this.panelSwitcherBar.push(panels.map(panel => {
I
isidor 已提交
186
			const action = this.instantiationService.createInstance(OpenPanelAction, panel);
I
isidor 已提交
187

188
			this.panelIdToActions[panel.id] = action;
B
Benjamin Pasero 已提交
189
			this.toUnbind.push(action);
I
isidor 已提交
190

191
			return action;
B
Benjamin Pasero 已提交
192
		}));
I
isidor 已提交
193
	}
194 195 196 197
}

registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {

198 199 200 201 202 203 204 205 206 207 208 209 210 211
	// Panel Background: since panels can host editors, we apply a background rule if the panel background
	// color is different from the editor background color. This is a bit of a hack though. The better way
	// would be to have a way to push the background color onto each editor widget itself somehow.
	const panelBackground = theme.getColor(PANEL_BACKGROUND);
	if (panelBackground && panelBackground !== theme.getColor(editorBackground)) {
		collector.addRule(`
			.monaco-workbench > .part.panel > .content .monaco-editor,
			.monaco-workbench > .part.panel > .content .monaco-editor .margin,
			.monaco-workbench > .part.panel > .content .monaco-editor .monaco-editor-background {
				background-color: ${panelBackground};
			}
		`);
	}

212
	// Title Active
213
	const titleActive = theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND);
214
	const titleActiveBorder = theme.getColor(PANEL_ACTIVE_TITLE_BORDER);
215 216 217 218 219 220 221 222 223
	if (titleActive || titleActiveBorder) {
		collector.addRule(`
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:hover .action-label,
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label.checked {
				color: ${titleActive};
				border-bottom-color: ${titleActiveBorder};
			}
		`);
	}
224 225

	// Title Inactive
226
	const titleInactive = theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND);
227 228 229 230 231 232 233
	if (titleInactive) {
		collector.addRule(`
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label {
				color: ${titleInactive};
			}
		`);
	}
234 235

	// Title focus
236
	const focusBorderColor = theme.getColor(focusBorder);
237 238 239 240 241 242 243 244 245 246
	if (focusBorderColor) {
		collector.addRule(`
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:focus {
				color: ${titleActive};
				border-bottom-color: ${focusBorderColor} !important;
				border-bottom: 1px solid;
				outline: none;
			}
		`);
	}
247

B
Benjamin Pasero 已提交
248
	// Styling with Outline color (e.g. high contrast theme)
249
	const outline = theme.getColor(activeContrastBorder);
B
Benjamin Pasero 已提交
250
	if (outline) {
251
		const outline = theme.getColor(activeContrastBorder);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

		collector.addRule(`
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label.checked,
			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover {
				outline-color: ${outline};
				outline-width: 1px;
				outline-style: solid;
				border-bottom: none;
				padding-bottom: 0;
				outline-offset: 3px;
			}

			.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover:not(.checked) {
				outline-style: dashed;
			}
		`);
	}
});