diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index d781bd7a2a96b..f1eb8279e820b 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -32,11 +32,21 @@ export interface ISplitViewOptions { proportionalLayout?: boolean; // default true } +/** + * Only used when `proportionalLayout` is false. + */ +export const enum LayoutPriority { + Normal, + Low, + High +} + export interface IView { readonly element: HTMLElement; readonly minimumSize: number; readonly maximumSize: number; readonly onDidChange: Event; + readonly priority?: LayoutPriority; layout(size: number, orientation: Orientation): void; } @@ -320,7 +330,7 @@ export class SplitView extends Disposable { private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void { const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); - this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex, highPriorityIndex); + this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, [lowPriorityIndex], [highPriorityIndex]); this.distributeEmptySpace(); this.layoutViews(); this.saveProportions(); @@ -331,7 +341,11 @@ export class SplitView extends Disposable { this.size = size; if (!this.proportions) { - this.resize(this.viewItems.length - 1, size - previousSize); + const indexes = range(this.viewItems.length); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.High); + + this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes); } else { for (let i = 0; i < this.viewItems.length; i++) { const item = this.viewItems[i]; @@ -502,8 +516,8 @@ export class SplitView extends Disposable { index: number, delta: number, sizes = this.viewItems.map(i => i.size), - lowPriorityIndex?: number, - highPriorityIndex?: number, + lowPriorityIndexes?: number[], + highPriorityIndexes?: number[], overloadMinDelta: number = Number.NEGATIVE_INFINITY, overloadMaxDelta: number = Number.POSITIVE_INFINITY ): number { @@ -514,14 +528,18 @@ export class SplitView extends Disposable { const upIndexes = range(index, -1); const downIndexes = range(index + 1, this.viewItems.length); - if (typeof highPriorityIndex === 'number') { - pushToStart(upIndexes, highPriorityIndex); - pushToStart(downIndexes, highPriorityIndex); + if (highPriorityIndexes) { + for (const index of highPriorityIndexes) { + pushToStart(upIndexes, index); + pushToStart(downIndexes, index); + } } - if (typeof lowPriorityIndex === 'number') { - pushToEnd(upIndexes, lowPriorityIndex); - pushToEnd(downIndexes, lowPriorityIndex); + if (lowPriorityIndexes) { + for (const index of lowPriorityIndexes) { + pushToEnd(upIndexes, index); + pushToEnd(downIndexes, index); + } } const upItems = upIndexes.map(i => this.viewItems[i]); diff --git a/src/vs/base/test/browser/ui/splitview/splitview.test.ts b/src/vs/base/test/browser/ui/splitview/splitview.test.ts index e3e9c6772f772..185c9f25aa47c 100644 --- a/src/vs/base/test/browser/ui/splitview/splitview.test.ts +++ b/src/vs/base/test/browser/ui/splitview/splitview.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Emitter } from 'vs/base/common/event'; -import { SplitView, IView, Orientation, Sizing } from 'vs/base/browser/ui/splitview/splitview'; +import { SplitView, IView, Orientation, Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; import { Sash, SashState } from 'vs/base/browser/ui/sash/sash'; class TestView implements IView { @@ -35,7 +35,8 @@ class TestView implements IView { constructor( private _minimumSize: number, - private _maximumSize: number + private _maximumSize: number, + readonly priority: LayoutPriority = LayoutPriority.Normal ) { assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size'); } @@ -466,4 +467,64 @@ suite('Splitview', () => { view2.dispose(); view1.dispose(); }); + + test('high layout priority', () => { + const view1 = new TestView(20, Number.POSITIVE_INFINITY); + const view2 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.High); + const view3 = new TestView(20, Number.POSITIVE_INFINITY); + const splitview = new SplitView(container, { proportionalLayout: false }); + splitview.layout(200); + + splitview.addView(view1, Sizing.Distribute); + splitview.addView(view2, Sizing.Distribute); + splitview.addView(view3, Sizing.Distribute); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + + splitview.layout(180); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + + splitview.layout(124); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]); + + splitview.layout(60); + assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]); + + splitview.layout(200); + assert.deepEqual([view1.size, view2.size, view3.size], [20, 160, 20]); + + splitview.dispose(); + view3.dispose(); + view2.dispose(); + view1.dispose(); + }); + + test('low layout priority', () => { + const view1 = new TestView(20, Number.POSITIVE_INFINITY); + const view2 = new TestView(20, Number.POSITIVE_INFINITY); + const view3 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.Low); + const splitview = new SplitView(container, { proportionalLayout: false }); + splitview.layout(200); + + splitview.addView(view1, Sizing.Distribute); + splitview.addView(view2, Sizing.Distribute); + splitview.addView(view3, Sizing.Distribute); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + + splitview.layout(180); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + + splitview.layout(132); + assert.deepEqual([view1.size, view2.size, view3.size], [44, 20, 68]); + + splitview.layout(60); + assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]); + + splitview.layout(200); + assert.deepEqual([view1.size, view2.size, view3.size], [20, 160, 20]); + + splitview.dispose(); + view3.dispose(); + view2.dispose(); + view1.dispose(); + }); }); \ No newline at end of file