未验证 提交 094f5ee8 编写于 作者: B Benjamin Pasero 提交者: GitHub

Merge pull request #40757 from SrTobi-Forks/master

added Center Mode (#15684)
......@@ -688,6 +688,7 @@ export class CodeMenu {
const fullscreen = new MenuItem(this.withKeybinding('workbench.action.toggleFullScreen', { label: this.mnemonicLabel(nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")), click: () => this.windowsMainService.getLastActiveWindow().toggleFullScreen(), enabled: this.windowsMainService.getWindowCount() > 0 }));
const toggleZenMode = this.createMenuItem(nls.localize('miToggleZenMode', "Toggle Zen Mode"), 'workbench.action.toggleZenMode');
const toggleCenteredLayout = this.createMenuItem(nls.localize('miToggleCenteredLayout', "Toggle Centered Layout"), 'workbench.action.toggleCenteredLayout');
const toggleMenuBar = this.createMenuItem(nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar"), 'workbench.action.toggleMenuBar');
const splitEditor = this.createMenuItem(nls.localize({ key: 'miSplitEditor', comment: ['&& denotes a mnemonic'] }, "Split &&Editor"), 'workbench.action.splitEditor');
const toggleEditorLayout = this.createMenuItem(nls.localize({ key: 'miToggleEditorLayout', comment: ['&& denotes a mnemonic'] }, "Toggle Editor Group &&Layout"), 'workbench.action.toggleEditorGroupLayout');
......@@ -747,6 +748,7 @@ export class CodeMenu {
__separator__(),
fullscreen,
toggleZenMode,
toggleCenteredLayout,
isWindows || isLinux ? toggleMenuBar : void 0,
__separator__(),
splitEditor,
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import nls = require('vs/nls');
import { Action } from 'vs/base/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IPartService } from 'vs/workbench/services/part/common/partService';
class ToggleCenteredLayout extends Action {
public static readonly ID = 'workbench.action.toggleCenteredLayout';
public static readonly LABEL = nls.localize('toggleCenteredLayout', "Toggle Centered Layout");
constructor(
id: string,
label: string,
@IPartService private partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
public run(): TPromise<any> {
this.partService.toggleCenteredEditorLayout();
return TPromise.as(null);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCenteredLayout, ToggleCenteredLayout.ID, ToggleCenteredLayout.LABEL), 'View: Toggle Centered Layout', nls.localize('view', "View"));
\ No newline at end of file
......@@ -25,6 +25,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl';
import { ITitleAreaControl } from 'vs/workbench/browser/parts/editor/titleControl';
import { NoTabsTitleControl } from 'vs/workbench/browser/parts/editor/noTabsTitleControl';
......@@ -37,6 +38,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { ResourcesDropHandler, LocalSelectionTransfer, DraggedEditorIdentifier } from 'vs/workbench/browser/dnd';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPartService } from 'vs/workbench/services/part/common/partService';
export enum Rochade {
NONE,
......@@ -87,11 +89,18 @@ export interface IEditorGroupsControl {
dispose(): void;
}
interface CenteredEditorLayoutData {
leftMarginRatio: number;
size: number;
}
/**
* Helper class to manage multiple side by side editors for the editor part.
*/
export class EditorGroupsControl extends Themable implements IEditorGroupsControl, IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider {
private static readonly CENTERED_EDITOR_LAYOUT_DATA_STORAGE_KEY = 'workbench.centerededitorlayout.layoutData';
private static readonly TITLE_AREA_CONTROL_KEY = '__titleAreaControl';
private static readonly PROGRESS_BAR_CONTROL_KEY = '__progressBar';
private static readonly INSTANTIATION_SERVICE_KEY = '__instantiationService';
......@@ -101,6 +110,8 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
private static readonly EDITOR_TITLE_HEIGHT = 35;
private static readonly CENTERED_EDITOR_MIN_MARGIN = 10;
private static readonly SNAP_TO_MINIMIZED_THRESHOLD_WIDTH = 50;
private static readonly SNAP_TO_MINIMIZED_THRESHOLD_HEIGHT = 20;
......@@ -125,6 +136,22 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
private sashTwo: Sash;
private startSiloThreeSize: number;
// if the centered editor layout is activated, the editor inside of silo ONE is centered
// the silo will then contain:
// [left margin]|[editor]|[right margin]
// - The size of the editor is defined by centeredEditorSize
// - The position is defined by the ratio centeredEditorLeftMarginRatio = left-margin/(left-margin + editor + right-margin).
// - The two sashes can be used to control the size and position of the editor inside of the silo.
// - In order to seperate the two sashes from the sashes that control the size of bordering widgets
// CENTERED_EDITOR_MIN_MARGIN is forced as a minimum size for the two margins.
private centeredEditorActive: boolean;
private centeredEditorSashLeft: Sash;
private centeredEditorSashRight: Sash;
private centeredEditorPreferedSize: number;
private centeredEditorLeftMarginRatio: number;
private centeredEditorDragStartPosition: number;
private centeredEditorDragStartSize: number;
private visibleEditors: BaseEditor[];
private lastActiveEditor: BaseEditor;
......@@ -144,6 +171,8 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
groupOrientation: GroupOrientation,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IPartService private partService: IPartService,
@IStorageService private storageServise: IStorageService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IExtensionService private extensionService: IExtensionService,
@IInstantiationService private instantiationService: IInstantiationService,
......@@ -971,39 +1000,72 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
// For each position
POSITIONS.forEach(position => {
const silo = this.silos[position];
// Containers (they contain everything and can move between silos)
const container = $(silo).div({ 'class': 'container' });
this.createSilo(position);
});
// InstantiationServices
const instantiationService = this.instantiationService.createChild(new ServiceCollection(
[IContextKeyService, this.contextKeyService.createScoped(container.getHTMLElement())]
));
container.setProperty(EditorGroupsControl.INSTANTIATION_SERVICE_KEY, instantiationService); // associate with container
// Update Styles
this.updateStyles();
}
// Title containers
const titleContainer = $(container).div({ 'class': 'title' });
if (this.tabOptions.showTabs) {
titleContainer.addClass('tabs');
}
if (this.tabOptions.showIcons) {
titleContainer.addClass('show-file-icons');
}
this.hookTitleDragListener(titleContainer);
private createSilo(position: Position): void {
const silo = this.silos[position];
// Title Control
this.createTitleControl(this.stacks.groupAt(position), silo, titleContainer, instantiationService);
// Containers (they contain everything and can move between silos)
const container = $(silo).div({ 'class': 'container' });
// Progress Bar
const progressBar = new ProgressBar($(container));
this.toUnbind.push(attachProgressBarStyler(progressBar, this.themeService));
progressBar.getContainer().hide();
container.setProperty(EditorGroupsControl.PROGRESS_BAR_CONTROL_KEY, progressBar); // associate with container
});
// InstantiationServices
const instantiationService = this.instantiationService.createChild(new ServiceCollection(
[IContextKeyService, this.contextKeyService.createScoped(container.getHTMLElement())]
));
container.setProperty(EditorGroupsControl.INSTANTIATION_SERVICE_KEY, instantiationService); // associate with container
// Update Styles
this.updateStyles();
// Title containers
const titleContainer = $(container).div({ 'class': 'title' });
if (this.tabOptions.showTabs) {
titleContainer.addClass('tabs');
}
if (this.tabOptions.showIcons) {
titleContainer.addClass('show-file-icons');
}
this.hookTitleDragListener(titleContainer);
// Title Control
this.createTitleControl(this.stacks.groupAt(position), silo, titleContainer, instantiationService);
// Progress Bar
const progressBar = new ProgressBar($(container));
this.toUnbind.push(attachProgressBarStyler(progressBar, this.themeService));
progressBar.getContainer().hide();
container.setProperty(EditorGroupsControl.PROGRESS_BAR_CONTROL_KEY, progressBar); // associate with container
// Sash for first position to support centered editor layout
if (position === Position.ONE) {
// Center Layout stuff
this.centeredEditorSashLeft = new Sash(container.getHTMLElement(), this, { baseSize: 5, orientation: Orientation.VERTICAL });
this.toUnbind.push(this.centeredEditorSashLeft.onDidStart(() => this.onCenterSashLeftDragStart()));
this.toUnbind.push(this.centeredEditorSashLeft.onDidChange((e: ISashEvent) => this.onCenterSashLeftDrag(e)));
this.toUnbind.push(this.centeredEditorSashLeft.onDidEnd(() => this.storeCenteredLayoutData()));
this.toUnbind.push(this.centeredEditorSashLeft.onDidReset(() => this.resetCenteredEditor()));
this.centeredEditorSashRight = new Sash(container.getHTMLElement(), this, { baseSize: 5, orientation: Orientation.VERTICAL });
this.toUnbind.push(this.centeredEditorSashRight.onDidStart(() => this.onCenterSashRightDragStart()));
this.toUnbind.push(this.centeredEditorSashRight.onDidChange((e: ISashEvent) => this.onCenterSashRightDrag(e)));
this.toUnbind.push(this.centeredEditorSashRight.onDidEnd(() => this.storeCenteredLayoutData()));
this.toUnbind.push(this.centeredEditorSashRight.onDidReset(() => this.resetCenteredEditor()));
this.centeredEditorActive = false;
this.centeredEditorLeftMarginRatio = 0.5;
this.centeredEditorPreferedSize = -1; // set this later if we know the container size
// Restore centered layout position and size
const centeredLayoutDataString = this.storageServise.get(EditorGroupsControl.CENTERED_EDITOR_LAYOUT_DATA_STORAGE_KEY, StorageScope.GLOBAL);
if (centeredLayoutDataString) {
const centeredLayout = <CenteredEditorLayoutData>JSON.parse(centeredLayoutDataString);
this.centeredEditorLeftMarginRatio = centeredLayout.leftMarginRatio;
this.centeredEditorPreferedSize = centeredLayout.size;
}
}
}
protected updateStyles(): void {
......@@ -1858,12 +1920,87 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
this.sashTwo.layout();
}
private get centeredEditorAvailableSize(): number {
return this.silosSize[Position.ONE] - EditorGroupsControl.CENTERED_EDITOR_MIN_MARGIN * 2;
}
private get centeredEditorSize(): number {
return Math.min(this.centeredEditorAvailableSize, this.centeredEditorPreferedSize);
}
private get centeredEditorPosition(): number {
return EditorGroupsControl.CENTERED_EDITOR_MIN_MARGIN + this.centeredEditorLeftMarginRatio * (this.centeredEditorAvailableSize - this.centeredEditorSize);
}
private get centeredEditorEndPosition(): number {
return this.centeredEditorPosition + this.centeredEditorSize;
}
private setCenteredEditorPositionAndSize(pos: number, size: number): void {
this.centeredEditorPreferedSize = Math.max(this.minSize, size);
pos -= EditorGroupsControl.CENTERED_EDITOR_MIN_MARGIN;
pos = Math.min(pos, this.centeredEditorAvailableSize - this.centeredEditorSize);
pos = Math.max(0, pos);
this.centeredEditorLeftMarginRatio = pos / (this.centeredEditorAvailableSize - this.centeredEditorSize);
this.layoutContainers();
}
private onCenterSashLeftDragStart(): void {
this.centeredEditorDragStartPosition = this.centeredEditorPosition;
this.centeredEditorDragStartSize = this.centeredEditorSize;
}
private onCenterSashLeftDrag(e: ISashEvent): void {
const minMargin = EditorGroupsControl.CENTERED_EDITOR_MIN_MARGIN;
const diffPos = e.currentX - e.startX;
const diffSize = -diffPos;
const pos = this.centeredEditorDragStartPosition + diffPos;
const size = this.centeredEditorDragStartSize + diffSize;
this.setCenteredEditorPositionAndSize(pos, pos <= minMargin ? size + pos - minMargin : size);
}
private onCenterSashRightDragStart(): void {
this.centeredEditorDragStartPosition = this.centeredEditorPosition;
this.centeredEditorDragStartSize = this.centeredEditorSize;
}
private onCenterSashRightDrag(e: ISashEvent): void {
const diffPos = e.currentX - e.startX;
const diffSize = diffPos;
const pos = this.centeredEditorDragStartPosition;
const maxSize = this.centeredEditorAvailableSize - this.centeredEditorDragStartPosition;
const size = Math.min(maxSize, this.centeredEditorDragStartSize + diffSize);
this.setCenteredEditorPositionAndSize(size < this.minSize ? pos + (size - this.minSize) : pos, size);
}
private storeCenteredLayoutData(): void {
const data: CenteredEditorLayoutData = {
leftMarginRatio: this.centeredEditorLeftMarginRatio,
size: this.centeredEditorSize
};
this.storageServise.store(EditorGroupsControl.CENTERED_EDITOR_LAYOUT_DATA_STORAGE_KEY, JSON.stringify(data), StorageScope.GLOBAL);
}
public getVerticalSashTop(sash: Sash): number {
return 0;
}
public getVerticalSashLeft(sash: Sash): number {
return sash === this.sashOne ? this.silosSize[Position.ONE] : this.silosSize[Position.TWO] + this.silosSize[Position.ONE];
switch (sash) {
case this.sashOne:
return this.silosSize[Position.ONE];
case this.sashTwo:
return this.silosSize[Position.TWO] + this.silosSize[Position.ONE];
case this.centeredEditorSashLeft:
return this.centeredEditorPosition;
case this.centeredEditorSashRight:
return this.centeredEditorEndPosition;
default:
return 0;
}
}
public getVerticalSashHeight(sash: Sash): number {
......@@ -2013,6 +2150,27 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
}
});
// Layout centered Editor (only in vertical layout when one group is opened)
const doCentering = this.layoutVertically && this.stacks.groups.length === 1 && this.partService.isEditorLayoutCentered();
if (doCentering && !this.centeredEditorActive) {
this.centeredEditorSashLeft.show();
this.centeredEditorSashRight.show();
// no size set yet. Calculate a default value
if (this.centeredEditorPreferedSize === -1) {
this.resetCenteredEditor(false);
}
} else if (!doCentering && this.centeredEditorActive) {
this.centeredEditorSashLeft.hide();
this.centeredEditorSashRight.hide();
}
this.centeredEditorActive = doCentering;
if (this.centeredEditorActive) {
this.centeredEditorSashLeft.layout();
this.centeredEditorSashRight.layout();
}
// Layout visible editors
POSITIONS.forEach(position => {
this.layoutEditor(position);
......@@ -2031,10 +2189,17 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
private layoutEditor(position: Position): void {
const editorSize = this.silosSize[position];
if (editorSize && this.visibleEditors[position]) {
const editor = this.visibleEditors[position];
if (editorSize && editor) {
let editorWidth = this.layoutVertically ? editorSize : this.dimension.width;
let editorHeight = (this.layoutVertically ? this.dimension.height : this.silosSize[position]) - EditorGroupsControl.EDITOR_TITLE_HEIGHT;
let editorPosition = 0;
if (this.centeredEditorActive) {
editorWidth = this.centeredEditorSize;
editorPosition = this.centeredEditorPosition;
}
if (position !== Position.ONE) {
if (this.layoutVertically) {
editorWidth--; // accomodate for 1px left-border in containers TWO, THREE when laying out vertically
......@@ -2043,8 +2208,18 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
}
}
this.visibleEditors[position].layout(new Dimension(editorWidth, editorHeight));
editor.getContainer().style({ 'margin-left': `${editorPosition}px`, 'width': `${editorWidth}px` });
editor.layout(new Dimension(editorWidth, editorHeight));
}
}
private resetCenteredEditor(layout: boolean = true) {
this.centeredEditorLeftMarginRatio = 0.5;
this.centeredEditorPreferedSize = Math.floor(this.dimension.width * 0.61);
if (layout) {
this.layoutContainers();
}
this.storageServise.remove(EditorGroupsControl.CENTERED_EDITOR_LAYOUT_DATA_STORAGE_KEY, StorageScope.GLOBAL);
}
public getInstantiationService(position: Position): IInstantiationService {
......
......@@ -159,6 +159,7 @@ export class Workbench implements IPartService {
private static readonly sidebarRestoreStorageKey = 'workbench.sidebar.restore';
private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centered.editorlayout.active';
private static readonly panelPositionStorageKey = 'workbench.panel.location';
private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
......@@ -212,6 +213,7 @@ export class Workbench implements IPartService {
private sideBarVisibleContext: IContextKey<boolean>;
private hasFilesToCreateOpenOrDiff: boolean;
private fontAliasing: FontAliasingOption;
private centeredEditorLayoutActive: boolean;
private zenMode: {
active: boolean;
transitionedToFullScreen: boolean;
......@@ -383,6 +385,11 @@ export class Workbench implements IPartService {
this.toggleZenMode(true);
}
// Restore Forced Editor Center Mode
if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.GLOBAL, false)) {
this.centeredEditorLayoutActive = true;
}
const onRestored = (error?: Error): IWorkbenchStartedInfo => {
this.workbenchCreated = true;
......@@ -664,6 +671,9 @@ export class Workbench implements IPartService {
wasSideBarVisible: false,
wasPanelVisible: false
};
// Centered Editor Layout
this.centeredEditorLayoutActive = false;
}
private setPanelPositionFromStorageOrConfig() {
......@@ -1356,6 +1366,17 @@ export class Workbench implements IPartService {
}
}
public isEditorLayoutCentered(): boolean {
return this.centeredEditorLayoutActive;
}
public toggleCenteredEditorLayout(): void {
this.centeredEditorLayoutActive = !this.centeredEditorLayoutActive;
this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, this.centeredEditorLayoutActive, StorageScope.GLOBAL);
this.layout();
}
// Resize requested part along the main axis
// layout will do all the math for us and adjusts the other Parts
public resizePart(part: Parts, sizeChange: number): void {
......
......@@ -129,6 +129,16 @@ export interface IPartService {
*/
toggleZenMode(): void;
/**
* Returns whether the centered editor layout is active.
*/
isEditorLayoutCentered(): boolean;
/**
* Toggles the workbench in and out of centered editor layout.
*/
toggleCenteredEditorLayout(): void;
/**
* Resizes currently focused part on main access
*/
......
......@@ -433,6 +433,10 @@ export class TestPartService implements IPartService {
public toggleZenMode(): void { }
public isEditorLayoutCentered(): boolean { return false; }
public toggleCenteredEditorLayout(): void { }
public resizePart(part: Parts, sizeChange: number): void { }
}
......
......@@ -31,6 +31,7 @@ import 'vs/workbench/browser/actions/toggleSidebarVisibility';
import 'vs/workbench/browser/actions/toggleSidebarPosition';
import 'vs/workbench/browser/actions/toggleEditorLayout';
import 'vs/workbench/browser/actions/toggleZenMode';
import 'vs/workbench/browser/actions/toggleCenteredLayout';
import 'vs/workbench/browser/actions/toggleTabsVisibility';
import 'vs/workbench/parts/preferences/electron-browser/preferences.contribution';
import 'vs/workbench/parts/preferences/browser/keybindingsEditorContribution';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册