Maximize editor group (#194894)

* Maximize editor

* unmaximze instead of exit maximize

* add tests

* 💄

* adopt changes

* 💄

* 💄

* 💄

* 💄

* 💄

* 💄

* move context key to WorkbenchContextKeysHandler

* 💄

* 💄

* bug fix

* 💄

* touch file to remove from diff

* test maximized group event

* Update editor group behavior

* 💄

* 💄

* 💄

* 💄

* 💄

* 💄

* setvisibility unmaximizes view if maximized

* Add visibility option to serialized branch node
and update gridview reconstruction behavior

* Fix arrangeGroups method signature

* Save maximized view by location

* Fix activeGroup check in EditorPart

* 💄

* 💄

* Add gridWidgetDisposables to prevent memory leaks.

* simplify GridView.setChildVisible

* Refactor Grid class to return IDisposable
from maximizeView method

* 💄

* move maximizing to gridview layer

* Fix trySet2x2 method to
exit maximized view before setting 2x2

* fix bug

* hasMaximizedGroup

* Refactor GridView for hasMaximizedView

* fix migrations

* Fix double click tab toggle
value in workbench editor

* 💄

* Fix editor group expansion test

* 💄

* 💄

* 💄

* Fix migration with new settings validation

---------

Co-authored-by: Benjamin Pasero <benjamin.pasero@microsoft.com>
Co-authored-by: João Moreno <joao.moreno@microsoft.com>
This commit is contained in:
Benjamin Simmonds
2023-10-23 12:37:17 +02:00
committed by GitHub
co-authored by Benjamin Pasero João Moreno
parent bf9068c750
commit 246abc0ecb
20 changed files with 700 additions and 97 deletions
+57 -8
View File
@@ -51,6 +51,7 @@ export interface GridLeafNode<T extends IView> {
readonly view: T;
readonly box: Box;
readonly cachedVisibleSize: number | undefined;
readonly maximized: boolean;
}
export interface GridBranchNode<T extends IView> {
@@ -288,6 +289,7 @@ export class Grid<T extends IView = IView> extends Disposable {
private didLayout = false;
readonly onDidChangeViewMaximized: Event<boolean>;
/**
* Create a new {@link Grid}. A grid must *always* have a view
* inside.
@@ -313,6 +315,7 @@ export class Grid<T extends IView = IView> extends Disposable {
this.onDidChange = this.gridview.onDidChange;
this.onDidScroll = this.gridview.onDidScroll;
this.onDidChangeViewMaximized = this.gridview.onDidChangeViewMaximized;
}
style(styles: IGridStyles): void {
@@ -545,9 +548,28 @@ export class Grid<T extends IView = IView> extends Disposable {
*
* @param view The reference {@link IView view}.
*/
isViewSizeMaximized(view: T): boolean {
isViewExpanded(view: T): boolean {
const location = this.getViewLocation(view);
return this.gridview.isViewSizeMaximized(location);
return this.gridview.isViewExpanded(location);
}
/**
* Returns whether the {@link IView view} is maximized.
*
* @param view The reference {@link IView view}.
*/
isViewMaximized(view: T): boolean {
const location = this.getViewLocation(view);
return this.gridview.isViewMaximized(location);
}
/**
* Returns whether the {@link IView view} is maximized.
*
* @param view The reference {@link IView view}.
*/
hasMaximizedView(): boolean {
return this.gridview.hasMaximizedView();
}
/**
@@ -577,14 +599,30 @@ export class Grid<T extends IView = IView> extends Disposable {
}
/**
* Maximize the size of a {@link IView view} by collapsing all other views
* Maximizes the specified view and hides all other views.
* @param view The view to maximize.
*/
maximizeView(view: T) {
if (this.views.size < 2) {
throw new Error('At least two views are required to maximize a view');
}
const location = this.getViewLocation(view);
this.gridview.maximizeView(location);
}
exitMaximizedView(): void {
this.gridview.exitMaximizedView();
}
/**
* Expand the size of a {@link IView view} by collapsing all other views
* to their minimum sizes.
*
* @param view The {@link IView view}.
*/
maximizeViewSize(view: T): void {
expandView(view: T): void {
const location = this.getViewLocation(view);
this.gridview.maximizeViewSize(location);
this.gridview.expandView(location);
}
/**
@@ -713,12 +751,14 @@ export interface ISerializedLeafNode {
data: any;
size: number;
visible?: boolean;
maximized?: boolean;
}
export interface ISerializedBranchNode {
type: 'branch';
data: ISerializedNode[];
size: number;
visible?: boolean;
}
export type ISerializedNode = ISerializedLeafNode | ISerializedBranchNode;
@@ -739,14 +779,23 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
const size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height;
if (!isGridBranchNode(node)) {
const serializedLeafNode: ISerializedLeafNode = { type: 'leaf', data: node.view.toJSON(), size };
if (typeof node.cachedVisibleSize === 'number') {
return { type: 'leaf', data: node.view.toJSON(), size: node.cachedVisibleSize, visible: false };
serializedLeafNode.size = node.cachedVisibleSize;
serializedLeafNode.visible = false;
} else if (node.maximized) {
serializedLeafNode.maximized = true;
}
return { type: 'leaf', data: node.view.toJSON(), size };
return serializedLeafNode;
}
return { type: 'branch', data: node.children.map(c => SerializableGrid.serializeNode(c, orthogonal(orientation))), size };
const data = node.children.map(c => SerializableGrid.serializeNode(c, orthogonal(orientation)));
if (data.some(c => c.visible !== false)) {
return { type: 'branch', data: data, size };
}
return { type: 'branch', data: data, size, visible: false };
}
/**
+156 -9
View File
@@ -148,12 +148,14 @@ export interface ISerializedLeafNode {
data: any;
size: number;
visible?: boolean;
maximized?: boolean;
}
export interface ISerializedBranchNode {
type: 'branch';
data: ISerializedNode[];
size: number;
visible?: boolean;
}
export type ISerializedNode = ISerializedLeafNode | ISerializedBranchNode;
@@ -180,6 +182,7 @@ export interface GridLeafNode {
readonly view: IView;
readonly box: Box;
readonly cachedVisibleSize: number | undefined;
readonly maximized: boolean;
}
export interface GridBranchNode {
@@ -284,11 +287,11 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
}
get minimumSize(): number {
return this.children.length === 0 ? 0 : Math.max(...this.children.map(c => c.minimumOrthogonalSize));
return this.children.length === 0 ? 0 : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.minimumOrthogonalSize : 0));
}
get maximumSize(): number {
return Math.min(...this.children.map(c => c.maximumOrthogonalSize));
return Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.maximumOrthogonalSize : Number.POSITIVE_INFINITY));
}
get priority(): LayoutPriority {
@@ -342,6 +345,10 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
private readonly _onDidChange = new Emitter<number | undefined>();
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
private readonly _onDidVisibilityChange = new Emitter<boolean>();
readonly onDidVisibilityChange: Event<boolean> = this._onDidVisibilityChange.event;
private readonly childrenVisibilityChangeDisposable: DisposableStore = new DisposableStore();
private _onDidScroll = new Emitter<void>();
private onDidScrollDisposable: IDisposable = Disposable.None;
readonly onDidScroll: Event<void> = this._onDidScroll.event;
@@ -427,7 +434,7 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
return {
view: childDescriptor.node,
size: childDescriptor.node.size,
visible: childDescriptor.node instanceof LeafNode && childDescriptor.visible !== undefined ? childDescriptor.visible : true
visible: childDescriptor.visible !== false
};
}),
size: this.orthogonalSize
@@ -579,8 +586,8 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
this.splitview.resizeView(index, size);
}
isChildSizeMaximized(index: number): boolean {
return this.splitview.isViewSizeMaximized(index);
isChildExpanded(index: number): boolean {
return this.splitview.isViewExpanded(index);
}
distributeViewSizes(recursive = false): void {
@@ -614,7 +621,15 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
return;
}
const wereAllChildrenHidden = this.splitview.contentSize === 0;
this.splitview.setViewVisible(index, visible);
const areAllChildrenHidden = this.splitview.contentSize === 0;
// If all children are hidden then the parent should hide the entire splitview
// If the entire splitview is hidden then the parent should show the splitview when a child is shown
if ((visible && wereAllChildrenHidden) || (!visible && areAllChildrenHidden)) {
this._onDidVisibilityChange.fire(visible);
}
}
getChildCachedVisibleSize(index: number): number | undefined {
@@ -651,6 +666,15 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
const onDidScroll = Event.any(Event.signal(this.splitview.onDidScroll), ...this.children.map(c => c.onDidScroll));
this.onDidScrollDisposable.dispose();
this.onDidScrollDisposable = onDidScroll(this._onDidScroll.fire, this._onDidScroll);
this.childrenVisibilityChangeDisposable.clear();
this.children.forEach((child, index) => {
if (child instanceof BranchNode) {
this.childrenVisibilityChangeDisposable.add(child.onDidVisibilityChange((visible) => {
this.setChildVisible(index, visible);
}));
}
});
}
trySet2x2(other: BranchNode): IDisposable {
@@ -714,7 +738,9 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
this._onDidChange.dispose();
this._onDidSashReset.dispose();
this._onDidVisibilityChange.dispose();
this.childrenVisibilityChangeDisposable.dispose();
this.splitviewSashResetDisposable.dispose();
this.childrenSashResetDisposable.dispose();
this.childrenChangeDisposable.dispose();
@@ -1128,6 +1154,11 @@ export class GridView implements IDisposable {
this.root.edgeSnapping = edgeSnapping;
}
private maximizedNode: LeafNode | undefined = undefined;
private readonly _onDidChangeViewMaximized = new Emitter<boolean>();
readonly onDidChangeViewMaximized = this._onDidChangeViewMaximized.event;
/**
* Create a new {@link GridView} instance.
*
@@ -1173,6 +1204,10 @@ export class GridView implements IDisposable {
* @param location The {@link GridLocation location} to insert the view on.
*/
addView(view: IView, size: number | Sizing, location: GridLocation): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
this.disposable2x2.dispose();
this.disposable2x2 = Disposable.None;
@@ -1226,6 +1261,10 @@ export class GridView implements IDisposable {
* @param sizing Whether to distribute other {@link IView view}'s sizes.
*/
removeView(location: GridLocation, sizing?: DistributeSizing | AutoSizing): IView {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
this.disposable2x2.dispose();
this.disposable2x2 = Disposable.None;
@@ -1312,6 +1351,10 @@ export class GridView implements IDisposable {
* @param to The index where the {@link IView view} should move to.
*/
moveView(parentLocation: GridLocation, from: number, to: number): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
const [, parent] = this.getNode(parentLocation);
if (!(parent instanceof BranchNode)) {
@@ -1330,6 +1373,10 @@ export class GridView implements IDisposable {
* @param to The {@link GridLocation location} of another view.
*/
swapViews(from: GridLocation, to: GridLocation): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
const [fromRest, fromIndex] = tail(from);
const [, fromParent] = this.getNode(fromRest);
@@ -1378,6 +1425,10 @@ export class GridView implements IDisposable {
* @param size The size the view should be. Optionally provide a single dimension.
*/
resizeView(location: GridLocation, size: Partial<IViewSize>): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
const [rest, index] = tail(location);
const [pathToParent, parent] = this.getNode(rest);
@@ -1443,7 +1494,11 @@ export class GridView implements IDisposable {
*
* @param location The {@link GridLocation location} of the view.
*/
maximizeViewSize(location: GridLocation): void {
expandView(location: GridLocation): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
const [ancestors, node] = this.getNode(location);
if (!(node instanceof LeafNode)) {
@@ -1460,7 +1515,12 @@ export class GridView implements IDisposable {
*
* @param location The {@link GridLocation location} of the view.
*/
isViewSizeMaximized(location: GridLocation): boolean {
isViewExpanded(location: GridLocation): boolean {
if (this.hasMaximizedView()) {
// No view can be expanded when a view is maximized
return false;
}
const [ancestors, node] = this.getNode(location);
if (!(node instanceof LeafNode)) {
@@ -1468,7 +1528,7 @@ export class GridView implements IDisposable {
}
for (let i = 0; i < ancestors.length; i++) {
if (!ancestors[i].isChildSizeMaximized(location[i])) {
if (!ancestors[i].isChildExpanded(location[i])) {
return false;
}
}
@@ -1476,6 +1536,80 @@ export class GridView implements IDisposable {
return true;
}
maximizeView(location: GridLocation) {
const [, nodeToMaximize] = this.getNode(location);
if (!(nodeToMaximize instanceof LeafNode)) {
throw new Error('Location is not a LeafNode');
}
if (this.maximizedNode === nodeToMaximize) {
return;
}
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
for (let i = 0; i < parent.children.length; i++) {
const child = parent.children[i];
if (child instanceof LeafNode) {
if (child !== exclude) {
parent.setChildVisible(i, false);
}
} else {
hideAllViewsBut(child, exclude);
}
}
}
hideAllViewsBut(this.root, nodeToMaximize);
this.maximizedNode = nodeToMaximize;
this._onDidChangeViewMaximized.fire(true);
}
exitMaximizedView(): void {
if (!this.maximizedNode) {
return;
}
this.maximizedNode = undefined;
// When hiding a view, it's previous size is cached.
// To restore the sizes of all views, they need to be made visible in reverse order.
function showViewsInReverseOrder(parent: BranchNode): void {
for (let index = parent.children.length - 1; index >= 0; index--) {
const child = parent.children[index];
if (child instanceof LeafNode) {
parent.setChildVisible(index, true);
} else {
showViewsInReverseOrder(child);
}
}
}
showViewsInReverseOrder(this.root);
this._onDidChangeViewMaximized.fire(false);
}
hasMaximizedView(): boolean {
return this.maximizedNode !== undefined;
}
/**
* Returns whether the {@link IView view} is maximized.
*
* @param location The {@link GridLocation location} of the view.
*/
isViewMaximized(location: GridLocation): boolean {
const [, node] = this.getNode(location);
if (!(node instanceof LeafNode)) {
throw new Error('Location is not a LeafNode');
}
return node === this.maximizedNode;
}
/**
* Distribute the size among all {@link IView views} within the entire
* grid or within a single {@link SplitView}.
@@ -1486,6 +1620,10 @@ export class GridView implements IDisposable {
* in the entire grid.
*/
distributeViewSizes(location?: GridLocation): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
}
if (!location) {
this.root.distributeViewSizes(true);
return;
@@ -1523,6 +1661,11 @@ export class GridView implements IDisposable {
* @param location The {@link GridLocation location} of the view.
*/
setViewVisible(location: GridLocation, visible: boolean): void {
if (this.hasMaximizedView()) {
this.exitMaximizedView();
return;
}
const [rest, index] = tail(location);
const [, parent] = this.getNode(rest);
@@ -1596,6 +1739,10 @@ export class GridView implements IDisposable {
result = new BranchNode(orientation, this.layoutController, this.styles, this.proportionalLayout, node.size, orthogonalSize, undefined, children);
} else {
result = new LeafNode(deserializer.fromJSON(node.data), orientation, this.layoutController, orthogonalSize, node.size);
if (node.maximized && !this.maximizedNode) {
this.maximizedNode = result;
this._onDidChangeViewMaximized.fire(true);
}
}
return result;
@@ -1605,7 +1752,7 @@ export class GridView implements IDisposable {
const box = { top: node.top, left: node.left, width: node.width, height: node.height };
if (node instanceof LeafNode) {
return { view: node.view, box, cachedVisibleSize };
return { view: node.view, box, cachedVisibleSize, maximized: this.maximizedNode === node };
}
const children: GridNode[] = [];
+16 -11
View File
@@ -442,7 +442,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
private scrollableElement: SmoothScrollableElement;
private size = 0;
private layoutContext: TLayoutContext | undefined;
private contentSize = 0;
private _contentSize = 0;
private proportions: (number | undefined)[] | undefined = undefined;
private viewItems: ViewItem<TLayoutContext, TView>[] = [];
sashItems: ISashItem[] = []; // used in tests
@@ -459,6 +459,11 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
private _startSnappingEnabled = true;
private _endSnappingEnabled = true;
/**
* The sum of all views' sizes.
*/
get contentSize(): number { return this._contentSize; }
/**
* Fires whenever the user resizes a {@link Sash sash}.
*/
@@ -624,7 +629,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
});
// Initialize content size and proportions for first layout
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
this.saveProportions();
}
}
@@ -834,7 +839,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
* @param layoutContext An optional layout context to pass along to {@link IView views}.
*/
layout(size: number, layoutContext?: TLayoutContext): void {
const previousSize = Math.max(this.size, this.contentSize);
const previousSize = Math.max(this.size, this._contentSize);
this.size = size;
this.layoutContext = layoutContext;
@@ -862,7 +867,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
const item = this.viewItems[i];
const proportion = this.proportions[i];
if (typeof proportion === 'number') {
if (typeof proportion === 'number' && total > 0) {
item.size = clamp(Math.round(proportion * size / total), item.minimumSize, item.maximumSize);
}
}
@@ -873,8 +878,8 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
}
private saveProportions(): void {
if (this.proportionalLayout && this.contentSize > 0) {
this.proportions = this.viewItems.map(i => i.proportionalLayout ? i.size / this.contentSize : undefined);
if (this.proportionalLayout && this._contentSize > 0) {
this.proportions = this.viewItems.map(v => v.proportionalLayout && v.visible ? v.size / this._contentSize : undefined);
}
}
@@ -1052,7 +1057,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
/**
* Returns whether all other {@link IView views} are at their minimum size.
*/
isViewSizeMaximized(index: number): boolean {
isViewExpanded(index: number): boolean {
if (index < 0 || index >= this.viewItems.length) {
return false;
}
@@ -1347,7 +1352,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
private layoutViews(): void {
// Save new content size
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
// Layout views
let offset = 0;
@@ -1367,12 +1372,12 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
if (this.orientation === Orientation.VERTICAL) {
this.scrollableElement.setScrollDimensions({
height: this.size,
scrollHeight: this.contentSize
scrollHeight: this._contentSize
});
} else {
this.scrollableElement.setScrollDimensions({
width: this.size,
scrollWidth: this.contentSize
scrollWidth: this._contentSize
});
}
}
@@ -1411,7 +1416,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
if (snappedBefore && collapsesUp[index] && (position > 0 || this.startSnappingEnabled)) {
sash.state = SashState.AtMinimum;
} else if (snappedAfter && collapsesDown[index] && (position < this.contentSize || this.endSnappingEnabled)) {
} else if (snappedAfter && collapsesDown[index] && (position < this._contentSize || this.endSnappingEnabled)) {
sash.state = SashState.AtMaximum;
} else {
sash.state = SashState.Disabled;
+201 -1
View File
@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { createSerializedGrid, Direction, getRelativeLocation, Grid, GridNode, GridNodeDescriptor, ISerializableView, isGridBranchNode, IViewDeserializer, Orientation, sanitizeGridNodeDescriptor, SerializableGrid, Sizing } from 'vs/base/browser/ui/grid/grid';
import { Event } from 'vs/base/common/event';
import { deepClone } from 'vs/base/common/objects';
import { nodesToArrays, TestView } from './util';
import { nodesToArrays, TestView } from 'vs/base/test/browser/ui/grid/util';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { DisposableStore } from 'vs/base/common/lifecycle';
@@ -464,6 +464,206 @@ suite('Grid', function () {
assert.deepStrictEqual(grid.getNeighborViews(view1, Direction.Right), [view2, view3]);
});
test('hiding splitviews and restoring sizes', function () {
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
const size1 = view1.size;
const size2 = view2.size;
const size3 = view3.size;
const size4 = view4.size;
grid.maximizeView(view1);
// Views 2, 3, 4 are hidden
// Splitview (2,4) and ((2,4),3) are hidden
assert.deepStrictEqual(view1.size, [800, 600]);
assert.deepStrictEqual(view2.size, [0, 0]);
assert.deepStrictEqual(view3.size, [0, 0]);
assert.deepStrictEqual(view4.size, [0, 0]);
grid.exitMaximizedView();
assert.deepStrictEqual(view1.size, size1);
assert.deepStrictEqual(view2.size, size2);
assert.deepStrictEqual(view3.size, size3);
assert.deepStrictEqual(view4.size, size4);
// Views 1, 3, 4 are hidden
// All splitviews are still visible => only orthogonalsize is 0
grid.maximizeView(view2);
assert.deepStrictEqual(view1.size, [0, 600]);
assert.deepStrictEqual(view2.size, [800, 600]);
assert.deepStrictEqual(view3.size, [800, 0]);
assert.deepStrictEqual(view4.size, [0, 600]);
grid.exitMaximizedView();
assert.deepStrictEqual(view1.size, size1);
assert.deepStrictEqual(view2.size, size2);
assert.deepStrictEqual(view3.size, size3);
assert.deepStrictEqual(view4.size, size4);
});
test('hasMaximizedView', function () {
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
function checkIsMaximized(view: TestView) {
grid.maximizeView(view);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
// When a view is maximized, no view can be expanded even if it is maximized
assert.deepStrictEqual(grid.isViewExpanded(view1), false);
assert.deepStrictEqual(grid.isViewExpanded(view2), false);
assert.deepStrictEqual(grid.isViewExpanded(view3), false);
assert.deepStrictEqual(grid.isViewExpanded(view4), false);
grid.exitMaximizedView();
assert.deepStrictEqual(grid.hasMaximizedView(), false);
}
checkIsMaximized(view1);
checkIsMaximized(view2);
checkIsMaximized(view3);
checkIsMaximized(view4);
});
test('Changes to the grid unmaximize the view', function () {
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
// Adding a view unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
assert.deepStrictEqual(grid.isViewVisible(view4), true);
// Removing a view unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.removeView(view4);
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
// Changing the visibility of any view while a view is maximized, unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.setViewVisible(view3, true);
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
});
test('Changes to the grid sizing unmaximize the view', function () {
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
// Maximizing a different view unmaximizes the current one and maximizes the new one
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.maximizeView(view2);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
assert.deepStrictEqual(grid.isViewVisible(view1), false);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), false);
assert.deepStrictEqual(grid.isViewVisible(view4), false);
// Distributing the size unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.distributeViewSizes();
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
assert.deepStrictEqual(grid.isViewVisible(view4), true);
// Expanding a different view unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.expandView(view2);
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
assert.deepStrictEqual(grid.isViewVisible(view4), true);
// Expanding the maximized view unmaximizes the view
grid.maximizeView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), true);
grid.expandView(view1);
assert.deepStrictEqual(grid.hasMaximizedView(), false);
assert.deepStrictEqual(grid.isViewVisible(view1), true);
assert.deepStrictEqual(grid.isViewVisible(view2), true);
assert.deepStrictEqual(grid.isViewVisible(view3), true);
assert.deepStrictEqual(grid.isViewVisible(view4), true);
});
});
class TestSerializableView extends TestView implements ISerializableView {
@@ -6,7 +6,7 @@
import * as assert from 'assert';
import { $ } from 'vs/base/browser/dom';
import { GridView, IView, Orientation, Sizing } from 'vs/base/browser/ui/grid/gridview';
import { nodesToArrays, TestView } from './util';
import { nodesToArrays, TestView } from 'vs/base/test/browser/ui/grid/util';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('Gridview', function () {
+5 -1
View File
@@ -7,7 +7,7 @@ import { Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, setConstant as setConstantContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys';
import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext } from 'vs/workbench/common/contextkeys';
import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, MaximizedEditorGroupContext, TitleBarVisibleContext } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType, onDidRegisterWindow } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -44,6 +44,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
private activeEditorGroupLast: IContextKey<boolean>;
private activeEditorGroupLocked: IContextKey<boolean>;
private multipleEditorGroupsContext: IContextKey<boolean>;
private maximizedEditorGroupContext: IContextKey<boolean>;
private editorsVisibleContext: IContextKey<boolean>;
@@ -136,6 +137,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.activeEditorGroupLast = ActiveEditorGroupLastContext.bindTo(this.contextKeyService);
this.activeEditorGroupLocked = ActiveEditorGroupLockedContext.bindTo(this.contextKeyService);
this.multipleEditorGroupsContext = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
this.maximizedEditorGroupContext = MaximizedEditorGroupContext.bindTo(this.contextKeyService);
// Working Copies
this.dirtyWorkingCopiesContext = DirtyWorkingCopiesContext.bindTo(this.contextKeyService);
@@ -233,6 +235,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
this._register(this.editorGroupService.onDidChangeActiveGroup(() => this.updateEditorGroupContextKeys()));
this._register(this.editorGroupService.onDidChangeGroupLocked(() => this.updateEditorGroupContextKeys()));
this._register(this.editorGroupService.onDidChangeGroupMaximized((maximized) => this.maximizedEditorGroupContext.set(maximized)));
this._register(this.editorGroupService.onDidChangeEditorPartOptions(() => this.updateEditorAreaContextKeys()));
this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => disposableStore.add(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(window.document), true)), { window, disposableStore: this._store }));
@@ -10,7 +10,7 @@ import { IEditorFactoryRegistry, EditorExtensions } from 'vs/workbench/common/ed
import {
TextCompareEditorActiveContext, ActiveEditorPinnedContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorAvailableEditorIdsContext,
MultipleEditorGroupsContext, ActiveEditorDirtyContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext,
EditorTabsVisibleContext, ActiveEditorLastInGroupContext
EditorTabsVisibleContext, ActiveEditorLastInGroupContext, MaximizedEditorGroupContext
} from 'vs/workbench/common/contextkeys';
import { SideBySideEditorInput, SideBySideEditorInputSerializer } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
@@ -40,13 +40,14 @@ import {
QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction,
ReOpenInTextEditorAction, DuplicateGroupDownAction, DuplicateGroupLeftAction, DuplicateGroupRightAction, DuplicateGroupUpAction, ToggleEditorTypeAction, SplitEditorToAboveGroupAction, SplitEditorToBelowGroupAction,
SplitEditorToFirstGroupAction, SplitEditorToLastGroupAction, SplitEditorToLeftGroupAction, SplitEditorToNextGroupAction, SplitEditorToPreviousGroupAction, SplitEditorToRightGroupAction, NavigateForwardInEditsAction,
NavigateBackwardsInEditsAction, NavigateForwardInNavigationsAction, NavigateBackwardsInNavigationsAction, NavigatePreviousInNavigationsAction, NavigatePreviousInEditsAction, NavigateToLastNavigationLocationAction, ExperimentalMoveEditorIntoNewWindowAction
NavigateBackwardsInEditsAction, NavigateForwardInNavigationsAction, NavigateBackwardsInNavigationsAction, NavigatePreviousInNavigationsAction, NavigatePreviousInEditsAction, NavigateToLastNavigationLocationAction,
MaximizeGroupHideSidebarAction, UnmaximizeEditorGroupAction, ExperimentalMoveEditorIntoNewWindowAction
} from 'vs/workbench/browser/parts/editor/editorActions';
import {
CLOSE_EDITORS_AND_GROUP_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_EDITOR_GROUP_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID,
CLOSE_PINNED_EDITOR_COMMAND_ID, CLOSE_SAVED_EDITORS_COMMAND_ID, GOTO_NEXT_CHANGE, GOTO_PREVIOUS_CHANGE, KEEP_EDITOR_COMMAND_ID, PIN_EDITOR_COMMAND_ID, SHOW_EDITORS_IN_GROUP, SPLIT_EDITOR_DOWN, SPLIT_EDITOR_LEFT,
SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, TOGGLE_DIFF_SIDE_BY_SIDE, TOGGLE_KEEP_EDITORS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, setup as registerEditorCommands, REOPEN_WITH_COMMAND_ID,
TOGGLE_LOCK_GROUP_COMMAND_ID, UNLOCK_GROUP_COMMAND_ID, SPLIT_EDITOR_IN_GROUP, JOIN_EDITOR_IN_GROUP, FOCUS_FIRST_SIDE_EDITOR, FOCUS_SECOND_SIDE_EDITOR, TOGGLE_SPLIT_EDITOR_IN_GROUP_LAYOUT, SPLIT_EDITOR
TOGGLE_LOCK_GROUP_COMMAND_ID, UNLOCK_GROUP_COMMAND_ID, SPLIT_EDITOR_IN_GROUP, JOIN_EDITOR_IN_GROUP, FOCUS_FIRST_SIDE_EDITOR, FOCUS_SECOND_SIDE_EDITOR, TOGGLE_SPLIT_EDITOR_IN_GROUP_LAYOUT, SPLIT_EDITOR, MAXIMIZE_EDITOR_GROUP, UNMAXIMIZE_EDITOR_GROUP
} from 'vs/workbench/browser/parts/editor/editorCommands';
import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -214,6 +215,8 @@ registerAction2(NavigateBetweenGroupsAction);
registerAction2(ResetGroupSizesAction);
registerAction2(ToggleGroupSizesAction);
registerAction2(MaximizeGroupAction);
registerAction2(UnmaximizeEditorGroupAction);
registerAction2(MaximizeGroupHideSidebarAction);
registerAction2(MinimizeOtherGroupsAction);
registerAction2(MoveEditorLeftInGroupAction);
@@ -382,7 +385,9 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: SHOW_EDITORS_IN
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeAll', "Close All") }, group: '5_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_KEEP_EDITORS_COMMAND_ID, title: localize('togglePreviewMode', "Enable Preview Editors"), toggled: ContextKeyExpr.has('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('lockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '8_lock', order: 10, when: MultipleEditorGroupsContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: MAXIMIZE_EDITOR_GROUP, title: localize('maximizeGroup', "Maximize Group") }, group: '8_group_operations', order: 5, when: ContextKeyExpr.and(MaximizedEditorGroupContext.negate(), MultipleEditorGroupsContext) });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: UNMAXIMIZE_EDITOR_GROUP, title: localize('unmaximizeGroup', "Unmaximize Group") }, group: '8_group_operations', order: 5, when: MaximizedEditorGroupContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('lockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '8_group_operations', order: 10, when: MultipleEditorGroupsContext });
function appendEditorToolItem(primary: ICommandAction, when: ContextKeyExpression | undefined, order: number, alternative?: ICommandAction, precondition?: ContextKeyExpression | undefined): void {
const item: IMenuItem = {
@@ -48,7 +48,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
splitSizing: 'auto',
splitOnDragAndDrop: true,
centeredLayoutFixedWidth: false,
doubleClickTabToToggleEditorGroupSizes: true,
doubleClickTabToToggleEditorGroupSizes: 'expand',
};
export function impactsEditorPartOptions(event: IConfigurationChangeEvent): boolean {
@@ -116,7 +116,6 @@ function validateEditorPartOptions(options: IEditorPartOptions): void {
'restoreViewState',
'splitOnDragAndDrop',
'centeredLayoutFixedWidth',
'doubleClickTabToToggleEditorGroupSizes'
];
for (const option of booleanOptions) {
if (typeof option === 'string') {
@@ -149,6 +148,7 @@ function validateEditorPartOptions(options: IEditorPartOptions): void {
['labelFormat', ['default', 'short', 'medium', 'long']],
['splitInGroupLayout', ['vertical', 'horizontal']],
['splitSizing', ['distribute', 'split', 'auto']],
['doubleClickTabToToggleEditorGroupSizes', ['maximize', 'expand', 'off']]
];
for (const [option, allowed] of stringOptions) {
if (typeof option === 'string') {
@@ -235,6 +235,8 @@ export interface IEditorGroupsView {
removeGroup(group: IEditorGroupView | GroupIdentifier): void;
arrangeGroups(arrangement: GroupsArrangement, target?: IEditorGroupView | GroupIdentifier): void;
toggleMaximizeGroup(group?: IEditorGroupView | GroupIdentifier): void;
toggleExpandGroup(group?: IEditorGroupView | GroupIdentifier): void;
}
export interface IEditorGroupTitleHeight {
@@ -13,7 +13,7 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro
import { GoFilter, IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveCopyArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, COPY_ACTIVE_EDITOR_COMMAND_ID, SPLIT_EDITOR } from 'vs/workbench/browser/parts/editor/editorCommands';
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveCopyArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, COPY_ACTIVE_EDITOR_COMMAND_ID, SPLIT_EDITOR, UNMAXIMIZE_EDITOR_GROUP, MAXIMIZE_EDITOR_GROUP, resolveCommandsContext, getCommandsContext } from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -33,7 +33,8 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ILogService } from 'vs/platform/log/common/log';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { ActiveEditorAvailableEditorIdsContext, ActiveEditorContext, ActiveEditorGroupEmptyContext } from 'vs/workbench/common/contextkeys';
import { ActiveEditorAvailableEditorIdsContext, ActiveEditorContext, ActiveEditorGroupEmptyContext, MaximizedEditorGroupContext, MultipleEditorGroupsContext } from 'vs/workbench/common/contextkeys';
import { URI } from 'vs/base/common/uri';
import { getActiveDocument } from 'vs/base/browser/dom';
class ExecuteCommandAction extends Action2 {
@@ -1014,7 +1015,7 @@ export class MinimizeOtherGroupsAction extends Action2 {
constructor() {
super({
id: 'workbench.action.minimizeOtherEditors',
title: { value: localize('minimizeOtherEditorGroups', "Maximize Editor Group"), original: 'Maximize Editor Group' },
title: { value: localize('minimizeOtherEditorGroups', "Expand Editor Group"), original: 'Expand Editor Group' },
f1: true,
category: Categories.View
});
@@ -1023,7 +1024,7 @@ export class MinimizeOtherGroupsAction extends Action2 {
override async run(accessor: ServicesAccessor): Promise<void> {
const editorGroupService = accessor.get(IEditorGroupsService);
editorGroupService.arrangeGroups(GroupsArrangement.MAXIMIZE);
editorGroupService.arrangeGroups(GroupsArrangement.EXPAND);
}
}
@@ -1059,7 +1060,7 @@ export class ToggleGroupSizesAction extends Action2 {
override async run(accessor: ServicesAccessor): Promise<void> {
const editorGroupService = accessor.get(IEditorGroupsService);
editorGroupService.arrangeGroups(GroupsArrangement.TOGGLE);
editorGroupService.toggleExpandGroup();
}
}
@@ -1067,10 +1068,34 @@ export class MaximizeGroupAction extends Action2 {
constructor() {
super({
id: 'workbench.action.maximizeEditor',
title: { value: localize('maximizeEditor', "Maximize Editor Group and Hide Side Bars"), original: 'Maximize Editor Group and Hide Side Bars' },
id: MAXIMIZE_EDITOR_GROUP,
title: { value: localize('maximizeEditor', "Maximize Editor Group"), original: 'Maximize Editor Group' },
f1: true,
category: Categories.View
category: Categories.View,
precondition: ContextKeyExpr.and(MaximizedEditorGroupContext.negate(), MultipleEditorGroupsContext),
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyM),
}
});
}
override async run(accessor: ServicesAccessor, resourceOrContext?: URI | IEditorCommandsContext, context?: IEditorCommandsContext): Promise<void> {
const editorsGroupService = accessor.get(IEditorGroupsService);
const { group } = resolveCommandsContext(editorsGroupService, getCommandsContext(resourceOrContext, context));
editorsGroupService.arrangeGroups(GroupsArrangement.MAXIMIZE, group);
}
}
export class MaximizeGroupHideSidebarAction extends Action2 {
constructor() {
super({
id: 'workbench.action.maximizeEditorHideSidebar',
title: { value: localize('maximizeEditorHideSidebar', "Maximize Editor Group and Hide Side Bars"), original: 'Maximize Editor Group and Hide Side Bars' },
f1: true,
category: Categories.View,
precondition: ContextKeyExpr.and(MaximizedEditorGroupContext.negate(), MultipleEditorGroupsContext)
});
}
@@ -1087,6 +1112,36 @@ export class MaximizeGroupAction extends Action2 {
}
}
export class UnmaximizeEditorGroupAction extends Action2 {
constructor() {
super({
id: UNMAXIMIZE_EDITOR_GROUP,
title: { value: localize('UnmaximizeEditorGroup', "Unmaximize Editor Group"), original: 'Unmaximize Editor Group' },
f1: true,
category: Categories.View,
precondition: MaximizedEditorGroupContext,
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyM),
},
menu: {
id: MenuId.EditorTitle,
order: -10000, // towards the front
group: 'navigation',
when: MaximizedEditorGroupContext
},
icon: Codicon.screenFull,
toggled: MaximizedEditorGroupContext,
});
}
override async run(accessor: ServicesAccessor): Promise<void> {
const editorGroupService = accessor.get(IEditorGroupsService);
editorGroupService.toggleMaximizeGroup();
}
}
abstract class AbstractNavigateEditorAction extends Action2 {
override async run(accessor: ServicesAccessor): Promise<void> {
@@ -80,6 +80,9 @@ export const SPLIT_EDITOR_DOWN = 'workbench.action.splitEditorDown';
export const SPLIT_EDITOR_LEFT = 'workbench.action.splitEditorLeft';
export const SPLIT_EDITOR_RIGHT = 'workbench.action.splitEditorRight';
export const MAXIMIZE_EDITOR_GROUP = 'workbench.action.maximizeEditorGroup';
export const UNMAXIMIZE_EDITOR_GROUP = 'workbench.action.unmaximizeEditorGroup';
export const SPLIT_EDITOR_IN_GROUP = 'workbench.action.splitEditorInGroup';
export const TOGGLE_SPLIT_EDITOR_IN_GROUP = 'workbench.action.toggleSplitEditorInGroup';
export const JOIN_EDITOR_IN_GROUP = 'workbench.action.joinEditorInGroup';
@@ -104,7 +107,8 @@ export const EDITOR_CORE_NAVIGATION_COMMANDS = [
SPLIT_EDITOR,
CLOSE_EDITOR_COMMAND_ID,
UNPIN_EDITOR_COMMAND_ID,
UNLOCK_GROUP_COMMAND_ID
UNLOCK_GROUP_COMMAND_ID,
UNMAXIMIZE_EDITOR_GROUP
];
export interface ActiveEditorMoveCopyArguments {
@@ -1464,7 +1468,7 @@ function getEditorsContext(accessor: ServicesAccessor, resourceOrContext?: URI |
};
}
function getCommandsContext(resourceOrContext?: URI | IEditorCommandsContext, context?: IEditorCommandsContext): IEditorCommandsContext | undefined {
export function getCommandsContext(resourceOrContext?: URI | IEditorCommandsContext, context?: IEditorCommandsContext): IEditorCommandsContext | undefined {
if (URI.isUri(resourceOrContext)) {
return context;
}
@@ -1480,7 +1484,7 @@ function getCommandsContext(resourceOrContext?: URI | IEditorCommandsContext, co
return undefined;
}
function resolveCommandsContext(editorGroupService: IEditorGroupsService, context?: IEditorCommandsContext): { group: IEditorGroup; editor?: EditorInput } {
export function resolveCommandsContext(editorGroupService: IEditorGroupsService, context?: IEditorCommandsContext): { group: IEditorGroup; editor?: EditorInput } {
// Resolve from context
let group = context && typeof context.groupId === 'number' ? editorGroupService.getGroup(context.groupId) : undefined;
@@ -101,6 +101,9 @@ export class EditorPart extends Part implements IEditorPart {
private readonly _onDidChangeGroupLocked = this._register(new Emitter<IEditorGroupView>());
readonly onDidChangeGroupLocked = this._onDidChangeGroupLocked.event;
private readonly _onDidChangeGroupMaximized = this._register(new Emitter<boolean>());
readonly onDidChangeGroupMaximized = this._onDidChangeGroupMaximized.event;
private readonly _onDidActivateGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidActivateGroup = this._onDidActivateGroup.event;
@@ -137,6 +140,7 @@ export class EditorPart extends Part implements IEditorPart {
private centeredLayoutWidget!: CenteredViewLayout;
private gridWidget!: SerializableGrid<IEditorGroupView>;
private readonly gridWidgetDisposables = this._register(new DisposableStore());
private readonly gridWidgetView = this._register(new GridWidgetView<IEditorGroupView>());
constructor(
@@ -147,7 +151,7 @@ export class EditorPart extends Part implements IEditorPart {
@IThemeService themeService: IThemeService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IStorageService storageService: IStorageService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
) {
super(id, { hasTitle: false }, themeService, storageService, layoutService);
@@ -369,21 +373,48 @@ export class EditorPart extends Part implements IEditorPart {
this.gridWidget.distributeViewSizes();
break;
case GroupsArrangement.MAXIMIZE:
this.gridWidget.maximizeViewSize(target);
break;
case GroupsArrangement.TOGGLE:
if (this.isGroupMaximized(target)) {
this.arrangeGroups(GroupsArrangement.EVEN);
} else {
this.arrangeGroups(GroupsArrangement.MAXIMIZE);
if (this.groups.length < 2) {
return; // need at least 2 groups to be maximized
}
this.gridWidget.maximizeView(target);
this.doSetGroupActive(target);
break;
case GroupsArrangement.EXPAND:
this.gridWidget.expandView(target);
break;
}
}
isGroupMaximized(targetGroup: IEditorGroupView): boolean {
return this.gridWidget.isViewSizeMaximized(targetGroup);
toggleMaximizeGroup(target: IEditorGroupView = this.activeGroup): void {
if (this.hasMaximizedGroup()) {
this.unmaximizeGroup();
} else {
this.arrangeGroups(GroupsArrangement.MAXIMIZE, target);
}
}
toggleExpandGroup(target: IEditorGroupView = this.activeGroup): void {
if (this.isGroupExpanded(this.activeGroup)) {
this.arrangeGroups(GroupsArrangement.EVEN);
} else {
this.arrangeGroups(GroupsArrangement.EXPAND, target);
}
}
private unmaximizeGroup(): void {
this.gridWidget.exitMaximizedView();
}
private hasMaximizedGroup(): boolean {
return this.gridWidget.hasMaximizedView();
}
private isGroupMaximized(targetGroup: IEditorGroupView): boolean {
return this.gridWidget.isViewMaximized(targetGroup);
}
isGroupExpanded(targetGroup: IEditorGroupView): boolean {
return this.gridWidget.isViewExpanded(targetGroup);
}
setGroupOrientation(orientation: GroupOrientation): void {
@@ -524,7 +555,7 @@ export class EditorPart extends Part implements IEditorPart {
if (locationView.groupsView === this) {
const restoreFocus = this.shouldRestoreFocus(locationView.element);
const shouldMaximize = this.groupViews.size > 1 && this.isGroupMaximized(locationView);
const shouldExpand = this.groupViews.size > 1 && this.isGroupExpanded(locationView);
newGroupView = this.doCreateGroupView(groupToCopy);
// Add to grid widget
@@ -544,9 +575,9 @@ export class EditorPart extends Part implements IEditorPart {
// Notify group index change given a new group was added
this.notifyGroupIndexChange();
// Maximize new group, if the reference view was previously maximized
if (shouldMaximize) {
this.arrangeGroups(GroupsArrangement.MAXIMIZE, newGroupView);
// Expand new group, if the reference view was previously expanded
if (shouldExpand) {
this.arrangeGroups(GroupsArrangement.EXPAND, newGroupView);
}
// Restore focus if we had it previously after completing the grid
@@ -642,7 +673,7 @@ export class EditorPart extends Part implements IEditorPart {
// Mark group as new active
group.setActive(true);
// Maximize the group if it is currently minimized
// Expand the group if it is currently minimized
this.doRestoreGroup(group);
// Event
@@ -657,9 +688,13 @@ export class EditorPart extends Part implements IEditorPart {
private doRestoreGroup(group: IEditorGroupView): void {
if (this.gridWidget) {
if (this.hasMaximizedGroup() && !this.isGroupMaximized(group)) {
this.unmaximizeGroup();
}
const viewSize = this.gridWidget.getViewSize(group);
if (viewSize.width === group.minimumWidth || viewSize.height === group.minimumHeight) {
this.arrangeGroups(GroupsArrangement.MAXIMIZE, group);
this.arrangeGroups(GroupsArrangement.EXPAND, group);
}
}
}
@@ -1032,6 +1067,10 @@ export class EditorPart extends Part implements IEditorPart {
}
centerLayout(active: boolean): void {
if (this.hasMaximizedGroup()) {
this.unmaximizeGroup();
}
this.centeredLayoutWidget.activate(active);
this._activeGroup.focus();
@@ -1158,6 +1197,10 @@ export class EditorPart extends Part implements IEditorPart {
this._onDidChangeSizeConstraints.input = gridWidget.onDidChange;
this._onDidScroll.input = gridWidget.onDidScroll;
this.gridWidgetDisposables.clear();
this.gridWidgetDisposables.add(gridWidget.onDidChangeViewMaximized(maximized => this._onDidChangeGroupMaximized.fire(maximized)));
this._onDidChangeGroupMaximized.fire(this.hasMaximizedGroup());
this.onDidSetGridWidget.fire(undefined);
}
@@ -97,6 +97,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
disposables.add(part.onDidRemoveGroup(group => this._onDidRemoveGroup.fire(group)));
disposables.add(part.onDidMoveGroup(group => this._onDidMoveGroup.fire(group)));
disposables.add(part.onDidActivateGroup(group => this._onDidActivateGroup.fire(group)));
disposables.add(part.onDidChangeGroupMaximized(maximized => this._onDidChangeGroupMaximized.fire(maximized)));
disposables.add(part.onDidChangeGroupIndex(group => this._onDidChangeGroupIndex.fire(group)));
disposables.add(part.onDidChangeGroupLocked(group => this._onDidChangeGroupLocked.fire(group)));
@@ -176,6 +177,9 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
private readonly _onDidChangeGroupLocked = this._register(new Emitter<IEditorGroupView>());
readonly onDidChangeGroupLocked = this._onDidChangeGroupLocked.event;
private readonly _onDidChangeGroupMaximized = this._register(new Emitter<boolean>());
readonly onDidChangeGroupMaximized = this._onDidChangeGroupMaximized.event;
//#endregion
//#region Editor Groups Service
@@ -227,11 +231,19 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
}
setSize(group: IEditorGroupView | GroupIdentifier, size: { width: number; height: number }): void {
return this.getPart(group).setSize(group, size);
this.getPart(group).setSize(group, size);
}
arrangeGroups(arrangement: GroupsArrangement): void {
return this.activePart.arrangeGroups(arrangement);
arrangeGroups(arrangement: GroupsArrangement, group?: IEditorGroupView): void {
(group !== undefined ? this.getPart(group) : this.activePart).arrangeGroups(arrangement, group);
}
toggleMaximizeGroup(group?: IEditorGroupView): void {
(group !== undefined ? this.getPart(group) : this.activePart).toggleMaximizeGroup(group);
}
toggleExpandGroup(group?: IEditorGroupView): void {
(group !== undefined ? this.getPart(group) : this.activePart).toggleExpandGroup(group);
}
restoreGroup(group: IEditorGroupView | GroupIdentifier): IEditorGroupView {
@@ -239,7 +251,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
}
applyLayout(layout: EditorGroupLayout): void {
return this.activePart.applyLayout(layout);
this.activePart.applyLayout(layout);
}
getLayout(): EditorGroupLayout {
@@ -247,7 +259,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
}
centerLayout(active: boolean): void {
return this.activePart.centerLayout(active);
this.activePart.centerLayout(active);
}
isLayoutCentered(): boolean {
@@ -259,7 +271,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
}
setGroupOrientation(orientation: GroupOrientation): void {
return this.activePart.setGroupOrientation(orientation);
this.activePart.setGroupOrientation(orientation);
}
findGroup(scope: IFindGroupScope, source?: IEditorGroupView | GroupIdentifier, wrap?: boolean): IEditorGroupView | undefined {
@@ -275,7 +287,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd
}
removeGroup(group: IEditorGroupView | GroupIdentifier): void {
return this.getPart(group).removeGroup(group);
this.getPart(group).removeGroup(group);
}
moveGroup(group: IEditorGroupView | GroupIdentifier, location: IEditorGroupView | GroupIdentifier, direction: GroupDirection): IEditorGroupView {
@@ -31,7 +31,7 @@ import { activeContrastBorder, contrastBorder, editorBackground } from 'vs/platf
import { ResourcesDropHandler, DraggedEditorIdentifier, DraggedEditorGroupIdentifier, extractTreeDropData } from 'vs/workbench/browser/dnd';
import { Color } from 'vs/base/common/color';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { MergeGroupMode, IMergeGroupOptions, GroupsArrangement, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { MergeGroupMode, IMergeGroupOptions, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { addDisposableListener, EventType, EventHelper, Dimension, scheduleAtNextAnimationFrame, findParentWithClass, clearNode, DragAndDropObserver, isMouseEvent } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { IEditorGroupsView, EditorServiceImpl, IEditorGroupView, IInternalEditorOpenOptions, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor';
@@ -992,9 +992,17 @@ export class MultiEditorTabsControl extends EditorTabsControl {
const editor = this.tabsModel.getEditorByIndex(tabIndex);
if (editor && this.tabsModel.isPinned(editor)) {
if (this.groupsView.partOptions.doubleClickTabToToggleEditorGroupSizes) {
this.groupsView.arrangeGroups(GroupsArrangement.TOGGLE, this.groupView);
switch (this.groupsView.partOptions.doubleClickTabToToggleEditorGroupSizes) {
case 'maximize':
this.groupsView.toggleMaximizeGroup(this.groupView);
break;
case 'expand':
this.groupsView.toggleExpandGroup(this.groupView);
break;
case 'off':
break;
}
} else {
this.groupView.pinEditor(editor);
}
@@ -322,9 +322,15 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
'description': localize('centeredLayoutDynamicWidth', "Controls whether the centered layout tries to maintain constant width when the window is resized.")
},
'workbench.editor.doubleClickTabToToggleEditorGroupSizes': {
'type': 'boolean',
'default': true,
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls whether to maximize/restore the editor group when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.")
'type': 'string',
'enum': ['maximize', 'expand', 'off'],
'default': 'expand',
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls how the editor group is resized when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."),
'enumDescriptions': [
localize('workbench.editor.doubleClickTabToToggleEditorGroupSizes.maximize', "All other editor groups are hidden and the current editor group is maximized to take up the entire editor area."),
localize('workbench.editor.doubleClickTabToToggleEditorGroupSizes.expand', "The editor group takes as much space as possible by making all other editor groups as small as possible."),
localize('workbench.editor.doubleClickTabToToggleEditorGroupSizes.off', "No editor group is resized when double clicking on a tab.")
]
},
'workbench.editor.limit.enabled': {
'type': 'boolean',
@@ -780,16 +786,20 @@ Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'workbench.editor.doubleClickTabToToggleEditorGroupSizes', migrateFn: (value: any) => {
if (typeof value === 'boolean') {
value = value ? 'expand' : 'off';
}
return [['workbench.editor.doubleClickTabToToggleEditorGroupSizes', { value: value }]];
}
}, {
key: 'workbench.editor.showTabs', migrateFn: (value: any) => {
if (typeof value === 'boolean') {
value = value ? 'multiple' : 'single';
}
return [['workbench.editor.showTabs', { value: value }]];
}
}]);
Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
.registerConfigurationMigrations([{
}, {
key: 'zenMode.hideTabs', migrateFn: (value: any) => {
const result: ConfigurationKeyValuePairs = [['zenMode.hideTabs', { value: undefined }]];
if (value === true) {
+1
View File
@@ -79,6 +79,7 @@ export const SplitEditorsVertically = new RawContextKey<boolean>('splitEditorsVe
export const EditorAreaVisibleContext = new RawContextKey<boolean>('editorAreaVisible', true, localize('editorAreaVisible', "Whether the editor area is visible"));
export const EditorTabsVisibleContext = new RawContextKey<boolean>('editorTabsVisible', true, localize('editorTabsVisible', "Whether editor tabs are visible"));
export const EditorPinnedAndUnpinnedTabsContext = new RawContextKey<boolean>('editorPinnedAndUnpinnedTabsVisible', false, true);
export const MaximizedEditorGroupContext = new RawContextKey<boolean>('maximizedEditorGroup', false, localize('editorGroupMaximized', "Editor group is maximized"));
//#endregion
+1 -1
View File
@@ -1139,7 +1139,7 @@ interface IEditorPartConfiguration {
splitSizing?: 'auto' | 'split' | 'distribute';
splitOnDragAndDrop?: boolean;
centeredLayoutFixedWidth?: boolean;
doubleClickTabToToggleEditorGroupSizes?: boolean;
doubleClickTabToToggleEditorGroupSizes?: 'maximize' | 'expand' | 'off';
limit?: IEditorPartLimitConfiguration;
decorations?: IEditorPartDecorationsConfiguration;
}
@@ -43,23 +43,22 @@ export interface IFindGroupScope {
}
export const enum GroupsArrangement {
/**
* Make the current active group consume the entire
* editor area.
*/
MAXIMIZE,
/**
* Make the current active group consume the maximum
* amount of space possible.
*/
MAXIMIZE,
EXPAND,
/**
* Size all groups evenly.
*/
EVEN,
/**
* Will behave like MINIMIZE_OTHERS if the active
* group is not already maximized and EVEN otherwise
*/
TOGGLE
EVEN
}
export interface GroupLayoutArgument {
@@ -215,6 +214,11 @@ export interface IEditorGroupsContainer {
*/
readonly onDidChangeGroupLocked: Event<IEditorGroup>;
/**
* An event for when the maximized state of a group changes.
*/
readonly onDidChangeGroupMaximized: Event<boolean>;
/**
* An active group is the default location for new editors to open.
*/
@@ -273,7 +277,17 @@ export interface IEditorGroupsContainer {
/**
* Arrange all groups in the container according to the provided arrangement.
*/
arrangeGroups(arrangement: GroupsArrangement): void;
arrangeGroups(arrangement: GroupsArrangement, target?: IEditorGroup | GroupIdentifier): void;
/**
* Toggles the target goup size to maximize/unmaximize.
*/
toggleMaximizeGroup(group?: IEditorGroup | GroupIdentifier): void;
/**
* Toggles the target goup size to expand/distribute even.
*/
toggleExpandGroup(group?: IEditorGroup | GroupIdentifier): void;
/**
* Applies the provided layout by either moving existing groups or creating new groups.
@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput, TestEditorPart, TestServiceAccessor, createEditorPart, ITestInstantiationService, workbenchTeardown } from 'vs/workbench/test/browser/workbenchTestServices';
import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupLocation, isEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupLocation, isEditorGroup, IEditorGroupsService, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService';
import { CloseDirection, IEditorPartOptions, EditorsOrder, EditorInputCapabilities, GroupModelChangeKind, SideBySideEditor } from 'vs/workbench/common/editor';
import { URI } from 'vs/base/common/uri';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
@@ -1718,5 +1718,44 @@ suite('EditorGroupsService', () => {
assert.strictEqual(rootGroup.isLocked, false);
});
test('maximize editor group', async () => {
const instantiationService = workbenchInstantiationService(undefined, disposables);
const [part] = await createPart(instantiationService);
const rootGroup = part.activeGroup;
const editorPartSize = part.getSize(rootGroup);
const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT);
const rightBottomGroup = part.addGroup(rightGroup, GroupDirection.DOWN);
const sizeRootGroup = part.getSize(rootGroup);
const sizeRightGroup = part.getSize(rightGroup);
const sizeRightBottomGroup = part.getSize(rightBottomGroup);
let maximizedValue;
const maxiizeGroupEventDisposable = part.onDidChangeGroupMaximized((maximized) => {
maximizedValue = maximized;
});
part.arrangeGroups(GroupsArrangement.MAXIMIZE, rootGroup);
// getSize()
assert.deepStrictEqual(part.getSize(rootGroup), editorPartSize);
assert.deepStrictEqual(part.getSize(rightGroup), { width: 0, height: 0 });
assert.deepStrictEqual(part.getSize(rightBottomGroup), { width: 0, height: 0 });
assert.deepStrictEqual(maximizedValue, true);
part.toggleMaximizeGroup();
// Size is restored
assert.deepStrictEqual(part.getSize(rootGroup), sizeRootGroup);
assert.deepStrictEqual(part.getSize(rightGroup), sizeRightGroup);
assert.deepStrictEqual(part.getSize(rightBottomGroup), sizeRightBottomGroup);
assert.deepStrictEqual(maximizedValue, false);
maxiizeGroupEventDisposable.dispose();
});
ensureNoDisposablesAreLeakedInTestSuite();
});
@@ -1691,7 +1691,7 @@ suite('EditorService', () => {
editor = await service.openEditor(input2, { pinned: true, activation: EditorActivation.ACTIVATE }, sideGroup);
assert.strictEqual(part.activeGroup, sideGroup);
part.arrangeGroups(GroupsArrangement.MAXIMIZE);
part.arrangeGroups(GroupsArrangement.EXPAND);
editor = await service.openEditor(input1, { pinned: true, preserveFocus: true, activation: EditorActivation.RESTORE }, rootGroup);
assert.strictEqual(part.activeGroup, sideGroup);
});
@@ -1711,13 +1711,13 @@ suite('EditorService', () => {
assert.strictEqual(part.activeGroup, sideGroup);
assert.notStrictEqual(rootGroup, sideGroup);
part.arrangeGroups(GroupsArrangement.MAXIMIZE, part.activeGroup);
part.arrangeGroups(GroupsArrangement.EXPAND, part.activeGroup);
await rootGroup.closeEditor(input2);
assert.strictEqual(part.activeGroup, sideGroup);
assert(!part.isGroupMaximized(rootGroup));
assert(part.isGroupMaximized(part.activeGroup));
assert(!part.isGroupExpanded(rootGroup));
assert(part.isGroupExpanded(part.activeGroup));
});
test('active editor change / visible editor change events', async function () {
@@ -824,6 +824,7 @@ export class TestEditorGroupsService implements IEditorGroupsService {
onDidMoveGroup: Event<IEditorGroup> = Event.None;
onDidChangeGroupIndex: Event<IEditorGroup> = Event.None;
onDidChangeGroupLocked: Event<IEditorGroup> = Event.None;
onDidChangeGroupMaximized: Event<boolean> = Event.None;
onDidLayout: Event<IDimension> = Event.None;
onDidChangeEditorPartOptions = Event.None;
onDidScroll = Event.None;
@@ -850,6 +851,8 @@ export class TestEditorGroupsService implements IEditorGroupsService {
getSize(_group: number | IEditorGroup): { width: number; height: number } { return { width: 100, height: 100 }; }
setSize(_group: number | IEditorGroup, _size: { width: number; height: number }): void { }
arrangeGroups(_arrangement: GroupsArrangement): void { }
toggleMaximizeGroup(): void { }
toggleExpandGroup(): void { }
applyLayout(_layout: EditorGroupLayout): void { }
getLayout(): EditorGroupLayout { throw new Error('not implemented'); }
setGroupOrientation(_orientation: GroupOrientation): void { }
@@ -966,6 +969,8 @@ export class TestEditorGroupAccessor implements IEditorGroupsView {
copyGroup(group: number | IEditorGroupView, location: number | IEditorGroupView, direction: GroupDirection): IEditorGroupView { throw new Error('Method not implemented.'); }
removeGroup(group: number | IEditorGroupView): void { throw new Error('Method not implemented.'); }
arrangeGroups(arrangement: GroupsArrangement, target?: number | IEditorGroupView | undefined): void { throw new Error('Method not implemented.'); }
toggleMaximizeGroup(group: number | IEditorGroupView): void { throw new Error('Method not implemented.'); }
toggleExpandGroup(group: number | IEditorGroupView): void { throw new Error('Method not implemented.'); }
}
export class TestEditorService implements EditorServiceImpl {