diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 1dae7da854faf3e2c9fb4c2ad27b5275518e1b9b..abd89ba63482e1fc23c3279b49885e19ac549e9e 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -838,8 +838,9 @@ declare module Electron { * at the current mouse cursor position. * @param x Horizontal coordinate where the menu will be placed. * @param y Vertical coordinate where the menu will be placed. + * @param positioningItem The item to select by default. */ - popup(browserWindow: BrowserWindow, x?: number, y?: number): void; + popup(browserWindow: BrowserWindow, x?: number, y?: number, positioningItem?: number): void; /** * Appends the menuItem to the menu. */ diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index fdb21f2092f4e91259c94f708fa9aaabca35abb1..8ce3af32df8c87125a492acfd52494558be440aa 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -970,6 +970,38 @@ export class ShowEditorsInRightGroupAction extends QuickOpenAction { } } +export class ShowEditorsInGroupAction extends Action { + + public static ID = 'workbench.action.showEditorsInGroup'; + public static LABEL = nls.localize('showEditorsInGroup', "Show Editors in Group"); + + constructor( + id: string, + label: string, + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IEditorGroupService private editorGroupService: IEditorGroupService + ) { + super(id, label); + } + + public run(context?: IEditorContext): TPromise { + const stacks = this.editorGroupService.getStacksModel(); + const groupCount = stacks.groups.length; + if (groupCount <= 1 || !context) { + return this.quickOpenService.show(NAVIGATE_ALL_EDITORS_GROUP_PREFIX); + } + + switch (stacks.positionOfGroup(context.group)) { + case Position.CENTER: + return this.quickOpenService.show((groupCount === 2) ? NAVIGATE_IN_RIGHT_GROUP_PREFIX : NAVIGATE_IN_CENTER_GROUP_PREFIX); + case Position.RIGHT: + return this.quickOpenService.show(NAVIGATE_IN_RIGHT_GROUP_PREFIX); + } + + return this.quickOpenService.show(NAVIGATE_IN_LEFT_GROUP_PREFIX); + } +} + export const NAVIGATE_ALL_EDITORS_GROUP_PREFIX = 'edt '; export class ShowAllEditorsAction extends QuickOpenAction { diff --git a/src/vs/workbench/browser/parts/editor/media/sidebyside.css b/src/vs/workbench/browser/parts/editor/media/sidebyside.css index 291000feff014970db3625e28262a8376d03970c..6856774592ee9a0be312f00b7ff92d679127b7f5 100644 --- a/src/vs/workbench/browser/parts/editor/media/sidebyside.css +++ b/src/vs/workbench/browser/parts/editor/media/sidebyside.css @@ -16,7 +16,6 @@ position: absolute; left: 0; width: 100%; - height: 100%; z-index: 3000000; } diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitle.css b/src/vs/workbench/browser/parts/editor/media/tabstitle.css index 5a9ceec494938a691f5e3f988da4948d962fc56c..4ec13f088bf866fe7880dae66714b7358a48050a 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitle.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitle.css @@ -11,11 +11,14 @@ .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container { display: flex; - /*overflow: scroll;*/ background-color: rgba(128, 128, 128, 0.2); height: 35px; } +.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container.scroll { + overflow: scroll !important; +} + .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container::-webkit-scrollbar { display: none; } @@ -36,10 +39,6 @@ padding-left: 10px; } -.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab:focus { - outline-offset: -2px; -} - .hc-black .monaco-workbench > .part.editor > .content > .one-editor-container > .title.active .tabs-container > .tab.active { border: 1px solid #f38518; } @@ -49,15 +48,19 @@ } .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.active { - border-bottom: 0; + border-bottom-color: transparent; opacity: 1 !important; } -.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container.dropfeedback, -.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.dropfeedback { +.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container.dropfeedback { background-color: rgba(51,153,255, 0.18); } +.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.dropfeedback { + background-color: rgba(187, 230, 255, 0.5); + opacity: 1 !important; +} + .vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container.dropfeedback, .vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.dropfeedback { background-color: rgba(83, 89, 93, 0.5); @@ -70,10 +73,6 @@ outline-offset: -2px; } -.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.dragged { - opacity: 0.7 !important; -} - /* Tab Close */ .monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab > .tab-close { diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts index 4015b662b0ae77afd77453d41687f561b3aed72c..be6d811fc4d824e633dd94bdcdce8759389f7afa 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts @@ -758,6 +758,7 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti const $this = this; const overlayId = 'monaco-workbench-editor-drop-overlay'; const splitToPropertyKey = 'splitToPosition'; + const stacks = this.editorGroupService.getStacksModel(); let overlay: Builder; function onDrop(e: DragEvent, position: Position, splitTo?: Position): void { @@ -766,7 +767,6 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti const editorService = $this.editorService; const groupService = $this.editorGroupService; - const stacks = groupService.getStacksModel(); const splitEditor = (typeof splitTo === 'number'); // TODO@Ben ugly split code should benefit from empty group support once available! const freeGroup = (stacks.groups.length === 1) ? Position.CENTER : Position.RIGHT; @@ -784,7 +784,7 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti if (splitTo !== freeGroup) { groupService.moveGroup(freeGroup, splitTo); } - }); + }).done(null, errors.onUnexpectedError); } else { editorService.openEditor(draggedEditor.editor, pinned, position).done(null, errors.onUnexpectedError); } @@ -794,12 +794,17 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti else { const sourcePosition = stacks.positionOfGroup(draggedEditor.group); if (splitEditor) { - editorService.openEditor(draggedEditor.editor, pinned, freeGroup).then(() => { - if (splitTo !== freeGroup) { - groupService.moveGroup(freeGroup, splitTo); - } - groupService.moveEditor(draggedEditor.editor, stacks.positionOfGroup(draggedEditor.group), splitTo); - }); + if (draggedEditor.group.count === 1) { + groupService.moveGroup(sourcePosition, splitTo); + } else { + editorService.openEditor(draggedEditor.editor, pinned, freeGroup).then(() => { + if (splitTo !== freeGroup) { + groupService.moveGroup(freeGroup, splitTo); + } + groupService.moveEditor(draggedEditor.editor, stacks.positionOfGroup(draggedEditor.group), splitTo); + }).done(null, errors.onUnexpectedError); + } + } else { groupService.moveEditor(draggedEditor.editor, sourcePosition, position); } @@ -840,39 +845,71 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti const overlayWidth = target.clientWidth; const splitThreshold = overlayIsSplit ? overlayWidth / 5 : overlayWidth / 10; const isCopy = (e.ctrlKey && !isMacintosh) || (e.altKey && isMacintosh); + const draggedEditor = TitleControl.getDraggedEditor(); - let allowSplit = true; + const isOverSplitLeft = posXOnOverlay < splitThreshold; + const isOverSplitRight = posXOnOverlay + splitThreshold > overlayWidth; + + let splitTarget: Position; + + // No splitting if we reached maximum group count if (groups === POSITIONS.length) { - allowSplit = false; // do not show split feedback when we already at the maximum + splitTarget = null; } - const draggedEditor = TitleControl.getDraggedEditor(); - if (!isCopy && draggedEditor && draggedEditor.group.count === 1) { - allowSplit = false; // do not show split feedback when moving the only one editor of a group + // Special splitting if we drag an editor of a group with only one editor + else if (!isCopy && draggedEditor && draggedEditor.group.count === 1) { + const positionOfDraggedEditor = stacks.positionOfGroup(draggedEditor.group); + switch (positionOfDraggedEditor) { + case Position.LEFT: + if (position === Position.CENTER && isOverSplitRight) { + splitTarget = Position.CENTER; // allow to move single editor from LEFT to CENTER + } + break; + case Position.CENTER: + if (position === Position.LEFT && isOverSplitLeft) { + splitTarget = Position.LEFT; // allow to move single editor from CENTER to LEFT + } + break; + default: + splitTarget = null; // splitting not allowed + } } - // Compute split decoration - if (allowSplit) { - if (posXOnOverlay + splitThreshold > overlayWidth) { - overlay.setProperty(splitToPropertyKey, position === Position.LEFT ? Position.CENTER : Position.RIGHT); - overlay.style({ - left: '50%', - width: '50%', - }); - } else if (posXOnOverlay < splitThreshold) { - overlay.setProperty(splitToPropertyKey, position === Position.LEFT ? Position.LEFT : Position.CENTER); - overlay.style({ - width: '50%' - }); - } else { - overlay.removeProperty(splitToPropertyKey); - overlay.style({ - left: '0', - width: '100%' - }); + // Any other case, check for mouse position + else { + if (isOverSplitRight) { + splitTarget = (position === Position.LEFT) ? Position.CENTER : Position.RIGHT; + } else if (isOverSplitLeft) { + splitTarget = (position === Position.LEFT) ? Position.LEFT : Position.CENTER; } } + // Apply split target + const canSplit = (typeof splitTarget === 'number'); + if (canSplit) { + overlay.setProperty(splitToPropertyKey, splitTarget); + } else { + overlay.removeProperty(splitToPropertyKey); + } + + // Update overlay styles + if (canSplit && isOverSplitRight) { + overlay.style({ + left: '50%', + width: '50%', + }); + } else if (canSplit && isOverSplitLeft) { + overlay.style({ + width: '50%' + }); + } else { + overlay.style({ + left: '0', + width: '100%' + }); + } + // Make sure the overlay is visible overlay.style({ opacity: 1 }); } @@ -885,7 +922,8 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti const useTabs = !!$this.configurationService.getConfiguration().workbench.editor.showTabs; overlay = $('div').style({ - top: useTabs ? SideBySideEditorControl.EDITOR_TITLE_HEIGHT + 'px' : 0 + top: useTabs ? SideBySideEditorControl.EDITOR_TITLE_HEIGHT + 'px' : 0, + height: useTabs ? `calc(100% - ${SideBySideEditorControl.EDITOR_TITLE_HEIGHT}px` : '100%' }).id(overlayId); overlay.appendTo(container); @@ -976,7 +1014,8 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti // Overlay the editor area with a div to be able to capture all mouse events let overlayDiv = $('div').style({ - top: SideBySideEditorControl.EDITOR_TITLE_HEIGHT + 'px' + top: SideBySideEditorControl.EDITOR_TITLE_HEIGHT + 'px', + height: '100%' }).id('monaco-workbench-editor-move-overlay'); overlayDiv.appendTo(this.parent); @@ -1122,8 +1161,12 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti // Move to valid position if any if (moveTo !== null) { this.editorGroupService.moveGroup(position, moveTo); - this.titleAreaControl[position].refresh(true); - this.titleAreaControl[moveTo].refresh(true); + + // To reduce flickering during this operation we trigger a refresh of all + // title controls right after. + POSITIONS.forEach(p => { + this.titleAreaControl[p].refresh(true); + }); } // Otherwise layout to restore proper positioning diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 2e8e005186fd1b3e31994733387b74c45d5ba1e3..5e304542ca7eb19e0e56459cede02bc8ca39405c 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -78,6 +78,14 @@ export class TabsTitleControl extends TitleControl { this.tabsContainer.setAttribute('role', 'tablist'); DOM.addClass(this.tabsContainer, 'tabs-container'); + this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.SCROLL, e => { + if (DOM.hasClass(this.tabsContainer, 'scroll')) { + this.scrollbar.updateState({ + scrollLeft: this.tabsContainer.scrollLeft // during DND the container gets scrolled so we need to update the custom scrollbar + }); + } + })); + // Custom Scrollbar this.scrollbar = new ScrollableElement(this.tabsContainer, { horizontal: ScrollbarVisibility.Auto, @@ -87,7 +95,6 @@ export class TabsTitleControl extends TitleControl { canUseTranslate3d: true, horizontalScrollbarSize: 3 }); - // this.tabsContainer.style.overflow = 'scroll'; // custom scrollbar is eager on removing this style but we want it for DND scroll feedback this.scrollbar.onScroll(e => { this.tabsContainer.scrollLeft = e.scrollLeft; @@ -97,6 +104,8 @@ export class TabsTitleControl extends TitleControl { // Drag over this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DRAG_OVER, (e: DragEvent) => { + DOM.addClass(this.tabsContainer, 'scroll'); // enable support to scroll while dragging + const target = e.target; if (target instanceof HTMLElement && target.className.indexOf('tabs-container') === 0) { DOM.addClass(this.tabsContainer, 'dropfeedback'); @@ -106,16 +115,19 @@ export class TabsTitleControl extends TitleControl { // Drag leave this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DRAG_LEAVE, (e: DragEvent) => { DOM.removeClass(this.tabsContainer, 'dropfeedback'); + DOM.removeClass(this.tabsContainer, 'scroll'); })); // Drag end this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DRAG_END, (e: DragEvent) => { DOM.removeClass(this.tabsContainer, 'dropfeedback'); + DOM.removeClass(this.tabsContainer, 'scroll'); })); // Drop onto tabs container this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DROP, (e: DragEvent) => { DOM.removeClass(this.tabsContainer, 'dropfeedback'); + DOM.removeClass(this.tabsContainer, 'scroll'); const target = e.target; if (target instanceof HTMLElement && target.className.indexOf('tabs-container') === 0) { @@ -339,10 +351,7 @@ export class TabsTitleControl extends TitleControl { // Update enablement of certain actions that depend on overflow const isOverflowing = (totalContainerWidth > visibleContainerWidth); - this.showEditorsOfLeftGroup.enabled = isOverflowing; - this.showEditorsOfCenterGroup.enabled = isOverflowing; - this.showEditorsOfRightGroup.enabled = isOverflowing; - this.showAllEditorsAction.enabled = isOverflowing; + this.showEditorsInGroupAction.enabled = isOverflowing; } private hookTabListeners(tab: HTMLElement, identifier: IEditorIdentifier): void { @@ -420,7 +429,6 @@ export class TabsTitleControl extends TitleControl { // Drag start this.tabDisposeables.push(DOM.addDisposableListener(tab, DOM.EventType.DRAG_START, (e: DragEvent) => { - DOM.addClass(tab, 'dragged'); this.onEditorDragStart({ editor, group }); e.dataTransfer.effectAllowed = 'copyMove'; @@ -443,13 +451,15 @@ export class TabsTitleControl extends TitleControl { // Drag end this.tabDisposeables.push(DOM.addDisposableListener(tab, DOM.EventType.DRAG_END, (e: DragEvent) => { - DOM.removeClass(tab, 'dragged'); DOM.removeClass(tab, 'dropfeedback'); + this.onEditorDragEnd(); })); // Drop this.tabDisposeables.push(DOM.addDisposableListener(tab, DOM.EventType.DROP, (e: DragEvent) => { + DOM.removeClass(tab, 'dropfeedback'); + const targetPosition = this.stacks.positionOfGroup(group); const targetIndex = group.indexOf(editor); diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 789fb025af6f767ef9a1d4c55323882559616220..1050cf3405e9b6003a94b156fcbbae7355f4fcec 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -15,7 +15,7 @@ import DOM = require('vs/base/browser/dom'); import {TPromise} from 'vs/base/common/winjs.base'; import {BaseEditor, IEditorInputActionContext} from 'vs/workbench/browser/parts/editor/baseEditor'; import {RunOnceScheduler} from 'vs/base/common/async'; -import {IEditorStacksModel, IEditorGroup, IEditorIdentifier, EditorInput, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor'; +import {IEditorStacksModel, IEditorGroup, IEditorIdentifier, EditorInput, IWorkbenchEditorConfiguration, IStacksModelChangeEvent} from 'vs/workbench/common/editor'; import {EventType as BaseEventType} from 'vs/base/common/events'; import {IActionItem, ActionsOrientation, Separator} from 'vs/base/browser/ui/actionbar/actionbar'; import {ToolBar} from 'vs/base/browser/ui/toolbar/toolbar'; @@ -25,14 +25,11 @@ import {Position} from 'vs/platform/editor/common/editor'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; import {IMessageService, Severity} from 'vs/platform/message/common/message'; -import {QuickOpenAction} from 'vs/workbench/browser/quickopen'; import {StandardMouseEvent} from 'vs/base/browser/mouseEvent'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService'; -import {ShowEditorsInLeftGroupAction, ShowAllEditorsAction, ShowEditorsInCenterGroupAction, ShowEditorsInRightGroupAction, CloseEditorsInGroupAction, MoveGroupLeftAction, - MoveGroupRightAction, SplitEditorAction, CloseEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, CloseRightEditorsInGroupAction} -from 'vs/workbench/browser/parts/editor/editorActions'; +import {CloseEditorsInGroupAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, CloseEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, CloseRightEditorsInGroupAction, ShowEditorsInGroupAction} from 'vs/workbench/browser/parts/editor/editorActions'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; export interface IToolbarActions { @@ -62,14 +59,11 @@ export abstract class TitleControl { protected pinEditorAction: KeepEditorAction; protected closeOtherEditorsAction: CloseOtherEditorsInGroupAction; protected closeRightEditorsAction: CloseRightEditorsInGroupAction; - protected showEditorsOfLeftGroup: QuickOpenAction; - protected showEditorsOfCenterGroup: QuickOpenAction; - protected showEditorsOfRightGroup: QuickOpenAction; protected moveGroupLeftAction: MoveGroupLeftAction; protected moveGroupRightAction: MoveGroupRightAction; protected closeEditorsInGroupAction: CloseEditorsInGroupAction; protected splitEditorAction: SplitEditorAction; - protected showAllEditorsAction: ShowAllEditorsAction; + protected showEditorsInGroupAction: ShowEditorsInGroupAction; private previewEditors: boolean; private showTabs: boolean; @@ -115,6 +109,13 @@ export abstract class TitleControl { private registerListeners(): void { this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(e.config))); + this.toDispose.push(this.stacks.onModelChanged(e => this.onStacksChanged(e))); + } + + private onStacksChanged(e: IStacksModelChangeEvent): void { + if (e.structural) { + this.updateSplitActionEnablement(); + } } private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { @@ -122,37 +123,18 @@ export abstract class TitleControl { this.showTabs = config.workbench.editor.showTabs; } - private updateActionEnablement(): void { + private updateSplitActionEnablement(): void { if (!this.context) { return; } - const group = this.context; const groupCount = this.stacks.groups.length; - // Move group - switch (this.stacks.positionOfGroup(group)) { - case Position.LEFT: - this.moveGroupLeftAction.enabled = false; - this.moveGroupRightAction.enabled = this.stacks.groups.length > 1; - break; - - case Position.CENTER: - this.moveGroupRightAction.enabled = this.stacks.groups.length > 2; - break; - - case Position.RIGHT: - this.moveGroupRightAction.enabled = false; - break; - } - // Split editor this.splitEditorAction.enabled = groupCount < 3; } private onSchedule(): void { - this.updateActionEnablement(); - if (this.refreshScheduled) { this.doRefresh(); } else { @@ -206,15 +188,12 @@ export abstract class TitleControl { this.closeRightEditorsAction = this.instantiationService.createInstance(CloseRightEditorsInGroupAction, CloseRightEditorsInGroupAction.ID, nls.localize('closeRight', "Close to the Right")); this.closeEditorsInGroupAction = this.instantiationService.createInstance(CloseEditorsInGroupAction, CloseEditorsInGroupAction.ID, nls.localize('closeAll', "Close All")); this.pinEditorAction = this.instantiationService.createInstance(KeepEditorAction, KeepEditorAction.ID, nls.localize('keepEditor', "Keep Editor")); - this.showAllEditorsAction = this.instantiationService.createInstance(ShowAllEditorsAction, ShowAllEditorsAction.ID, nls.localize('showEditors', "Show Editors")); + this.showEditorsInGroupAction = this.instantiationService.createInstance(ShowEditorsInGroupAction, ShowEditorsInGroupAction.ID, ShowEditorsInGroupAction.LABEL); this.splitEditorAction = this.instantiationService.createInstance(SplitEditorAction, SplitEditorAction.ID, SplitEditorAction.LABEL); this.moveGroupLeftAction = this.instantiationService.createInstance(MoveGroupLeftAction, MoveGroupLeftAction.ID, nls.localize('moveLeft', "Move Left")); this.moveGroupRightAction = this.instantiationService.createInstance(MoveGroupRightAction, MoveGroupRightAction.ID, nls.localize('moveRight', "Move Right")); - this.showEditorsOfLeftGroup = this.instantiationService.createInstance(ShowEditorsInLeftGroupAction, ShowEditorsInLeftGroupAction.ID, nls.localize('showEditors', "Show Editors")); - this.showEditorsOfCenterGroup = this.instantiationService.createInstance(ShowEditorsInCenterGroupAction, ShowEditorsInCenterGroupAction.ID, nls.localize('showEditors', "Show Editors")); - this.showEditorsOfRightGroup = this.instantiationService.createInstance(ShowEditorsInRightGroupAction, ShowEditorsInRightGroupAction.ID, nls.localize('showEditors', "Show Editors")); - [this.showEditorsOfLeftGroup, this.showEditorsOfCenterGroup, this.showEditorsOfRightGroup, this.showAllEditorsAction].forEach(a => a.class = 'show-group-editors-action'); + this.showEditorsInGroupAction.class = 'show-group-editors-action'; } protected doCreateToolbar(container: HTMLElement): ToolBar { @@ -328,35 +307,30 @@ export abstract class TitleControl { const editor = group.activeEditor; const primary: IAction[] = []; - const groupCount = this.stacks.groups.length; - // Overflow - let overflowAction: Action; - if (groupCount === 1) { - overflowAction = this.showAllEditorsAction; - } else { - switch (this.stacks.positionOfGroup(group)) { - case Position.LEFT: - overflowAction = this.showEditorsOfLeftGroup; - break; - - case Position.CENTER: - overflowAction = (groupCount === 2) ? this.showEditorsOfRightGroup : this.showEditorsOfCenterGroup; - break; - - case Position.RIGHT: - overflowAction = this.showEditorsOfRightGroup; - break; - } - } - - primary.push(overflowAction); + primary.push(this.showEditorsInGroupAction); // Splitting if (editor instanceof EditorInput && editor.supportsSplitEditor()) { primary.push(this.splitEditorAction); } + // Enablement + switch (this.stacks.positionOfGroup(group)) { + case Position.LEFT: + this.moveGroupLeftAction.enabled = false; + this.moveGroupRightAction.enabled = this.stacks.groups.length > 1; + break; + + case Position.CENTER: + this.moveGroupRightAction.enabled = this.stacks.groups.length > 2; + break; + + case Position.RIGHT: + this.moveGroupRightAction.enabled = false; + break; + } + // Return actions const secondary = [ this.moveGroupLeftAction, @@ -423,10 +397,7 @@ export abstract class TitleControl { // Actions [ this.splitEditorAction, - this.showAllEditorsAction, - this.showEditorsOfLeftGroup, - this.showEditorsOfCenterGroup, - this.showEditorsOfRightGroup, + this.showEditorsInGroupAction, this.closeEditorAction, this.closeRightEditorsAction, this.closeOtherEditorsAction, diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index a53028044da822b520e9a84a905b4a1c602f1fd3..ce8e106df469649a196bbbe442b1ddd5198ec02d 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -1541,13 +1541,18 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { const stacks = this.editorGroupService.getStacksModel(); // Store some properties per untitled file to restore later after save is completed - const mapUntitledToProperties: { [resource: string]: { mime: string; encoding: string; indexInGroups: number[]; } } = Object.create(null); + const mapUntitledToProperties: { [resource: string]: { mime: string; encoding: string; indexInGroups: number[]; activeInGroups: boolean[] } } = Object.create(null); this.textFileService.getDirty() .filter(r => r.scheme === 'untitled') // All untitled resources .map(r => this.untitledEditorService.get(r)) // Mapped to their inputs - .filter(i => !!i) // If possible :) - .forEach(i => { - mapUntitledToProperties[i.getResource().toString()] = { mime: i.getMime(), encoding: i.getEncoding(), indexInGroups: stacks.groups.map(g => g.indexOf(i)) }; + .filter(input => !!input) // If possible :) + .forEach(input => { + mapUntitledToProperties[input.getResource().toString()] = { + mime: input.getMime(), + encoding: input.getEncoding(), + indexInGroups: stacks.groups.map(g => g.indexOf(input)), + activeInGroups: stacks.groups.map(g => g.isActive(input)) + }; }); // Save all @@ -1582,7 +1587,8 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { options: { pinned: true, index: indexInGroup, - preserveFocus: true + preserveFocus: true, + inactive: !untitledProps.activeInGroups[index] } }, position: index diff --git a/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts index 953620e62098c0a0c62dea482b614e0a22430426..d1cd4a990ae42b67bdd0d1eda3a8068b02ab7d57 100644 --- a/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts @@ -57,7 +57,7 @@ export class ContextMenuService implements IContextMenuService { x *= zoom; y *= zoom; - menu.popup(remote.getCurrentWindow(), Math.floor(x), Math.floor(y)); + menu.popup(remote.getCurrentWindow(), Math.floor(x), Math.floor(y), -1 /* no item selected by default */); if (delegate.onHide) { delegate.onHide(undefined); }