Change:
Was finally able to repo this but not reliably. It seems to rely on a new being created, but this doesn't always happen. The most reliable repo for me: with a notebook and text editor in a single editor group the notebook editor down to create a new group below the text editor grab the notebook editor and drag it right to move the bottom editor to the right I think the root cause is that the notebook widget is passed the wrong position. I'm going to work around this by making the notebook editor ignore the position it is given, however this will also undo the performance fixes we made this iteration for notebook layout I don't fully understand the grid layout code but it seems that is being set incorrectly in cases where a new BranchNode/SplitView is created. Here's what I see happening after step 3 of the repo above: setter is called calls which creates a new the constructor, a new Split View is created is called on it. At this point, of the split view is: the time layout is called on the notebook editor widget, is computed as zero. This results in the wrong layout. Looking at the code, we can see that is passed in as the absolute offset in step 4: <img width="1104" alt="Screenshot 2022-11-30 at 12 48 54 PM" src="https://user-"If I then slightly resize the window, here's what happens: call on the split View for the new group now is: we layout the notebook editor, is now correctly computed as Originally posted by in

Discussion:
private _orthogonalSize: number; get orthogonalSize(): number { return this._orthogonalSize; } <del> private absoluteOffset: number = 0; private absoluteOrthogonalOffset: number = 0; </del> <ins> private _absoluteOffset: number = 0; get absoluteOffset(): number { return this._absoluteOffset; } private _absoluteOrthogonalOffset: number = 0; get absoluteOrthogonalOffset(): number { return this._absoluteOrthogonalOffset; } </ins> private absoluteOrthogonalSize: number = 0; private _styles: IGridViewStyles;

} get top(): number { <del> return this.orientation === Orientation.HORIZONTAL ? this.absoluteOffset : this.absoluteOrthogonalOffset; </del> <ins> return this.orientation === Orientation.HORIZONTAL ? this._absoluteOffset : this._absoluteOrthogonalOffset; </ins> } get left(): number { <del> return this.orientation === Orientation.HORIZONTAL ? this.absoluteOrthogonalOffset : this.absoluteOffset; </del> <ins> return this.orientation === Orientation.HORIZONTAL ? this._absoluteOrthogonalOffset : this._absoluteOffset; </ins> } get minimumSize(): number {

// branch nodes should flip the normal/orthogonal directions this._size = ctx.orthogonalSize; this._orthogonalSize = size; <del> this.absoluteOffset = ctx.absoluteOffset + offset; this.absoluteOrthogonalOffset = ctx.absoluteOrthogonalOffset; </del> <ins> this._absoluteOffset = ctx.absoluteOffset + offset; this._absoluteOrthogonalOffset = ctx.absoluteOrthogonalOffset; </ins> this.absoluteOrthogonalSize = ctx.absoluteOrthogonalSize; this.splitview.layout(ctx.orthogonalSize, { orthogonalSize: size, <del> absoluteOffset: this.absoluteOrthogonalOffset, absoluteOrthogonalOffset: this.absoluteOffset, </del> <ins> absoluteOffset: this._absoluteOrthogonalOffset, absoluteOrthogonalOffset: this._absoluteOffset, </ins> absoluteSize: ctx.absoluteOrthogonalSize, absoluteOrthogonalSize: ctx.absoluteSize });

} private updateSplitviewEdgeSnappingEnablement(): void { <del> this.splitview.startSnappingEnabled = this._edgeSnapping || this.absoluteOrthogonalOffset > 0; this.splitview.endSnappingEnabled = this._edgeSnapping || this.absoluteOrthogonalOffset + this._size < this.absoluteOrthogonalSize; </del> <ins> this.splitview.startSnappingEnabled = this._edgeSnapping || this._absoluteOrthogonalOffset > 0; this.splitview.endSnappingEnabled = this._edgeSnapping || this._absoluteOrthogonalOffset + this._size < this.absoluteOrthogonalSize; </ins> } dispose(): void {

return; } <del> const { size, orthogonalSize } = this._root; </del> <ins> const { size, orthogonalSize, absoluteOffset, absoluteOrthogonalOffset } = this._root; </ins> this.root = flipNode(this._root, orthogonalSize, size); <del> this.root.layout(size, 0, { orthogonalSize, absoluteOffset: 0, absoluteOrthogonalOffset: 0, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize }); </del> <ins> this.root.layout(size, 0, { orthogonalSize, absoluteOffset: absoluteOrthogonalOffset, absoluteOrthogonalOffset: absoluteOffset, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize }); </ins> this.boundarySashes = this.boundarySashes; }

import * as assert from 'assert'; import { $ } from 'vs/base/browser/dom'; <del> import { GridView, IView, Sizing } from 'vs/base/browser/ui/grid/gridview'; </del> <ins> import { GridView, IView, Orientation, Sizing } from 'vs/base/browser/ui/grid/gridview'; </ins> import { nodesToArrays, TestView } from './util'; suite('Gridview', function () {

assert.deepStrictEqual(view2.size, [400, 300]); assert.deepStrictEqual(view3.size, [400, 300]); }); <ins> test('flipping orientation should preserve absolute offsets', function () { const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [1]); gridview.layout(800, 600, 100, 200); assert.deepStrictEqual([view1.top, view1.left], [100, 200]); assert.deepStrictEqual([view2.top, view2.left], [100 + 300, 200]); gridview.orientation = Orientation.HORIZONTAL; assert.deepStrictEqual([view1.top, view1.left], [100, 200]); assert.deepStrictEqual([view2.top, view2.left], [100, 200 + 400]); }); </ins> });

private _height = 0; get height(): number { return this._height; } <ins> private _top = 0; get top(): number { return this._top; } private _left = 0; get left(): number { return this._left; } </ins> get size(): [number, number] { return [this.width, this.height]; } <del> private readonly _onDidLayout = new Emitter<{ width: number; height: number }>(); readonly onDidLayout: Event<{ width: number; height: number }> = this._onDidLayout.event; </del> <ins> private readonly _onDidLayout = new Emitter<{ width: number; height: number; top: number; left: number }>(); readonly onDidLayout: Event<{ width: number; height: number; top: number; left: number }> = this._onDidLayout.event; </ins> private readonly _onDidFocus = new Emitter<void>(); readonly onDidFocus: Event<void> = this._onDidFocus.event;

assert(_minimumHeight <= _maximumHeight, 'gridview view minimum height must be <= maximum height'); } <del> layout(width: number, height: number): void { </del> <ins> layout(width: number, height: number, top: number, left: number): void { </ins> this._width = width; this._height = height; <del> this._onDidLayout.fire({ width, height }); </del> <ins> this._top = top; this._left = left; this._onDidLayout.fire({ width, height, top, left }); </ins> } focus(): void {