mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 91e99652cd5fcfc072387c64e151b435e39e8dcf (#6962)
This commit is contained in:
@@ -7,7 +7,7 @@ import 'vs/css!./gridview';
|
||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { tail2 as tail, equals } from 'vs/base/common/arrays';
|
||||
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, LayoutController, IGridViewOptions } from './gridview';
|
||||
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions } from './gridview';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
|
||||
@@ -217,9 +217,17 @@ export class Grid<T extends IView = IView> extends Disposable {
|
||||
|
||||
private didLayout = false;
|
||||
|
||||
constructor(view: T, options: IGridOptions = {}) {
|
||||
constructor(gridview: GridView, options?: IGridOptions);
|
||||
constructor(view: T, options?: IGridOptions);
|
||||
constructor(view: T | GridView, options: IGridOptions = {}) {
|
||||
super();
|
||||
this.gridview = new GridView(options);
|
||||
|
||||
if (view instanceof GridView) {
|
||||
this.gridview = view;
|
||||
this.gridview.getViewMap(this.views);
|
||||
} else {
|
||||
this.gridview = new GridView(options);
|
||||
}
|
||||
this._register(this.gridview);
|
||||
|
||||
this._register(this.gridview.onDidSashReset(this.onDidSashReset, this));
|
||||
@@ -228,7 +236,9 @@ export class Grid<T extends IView = IView> extends Disposable {
|
||||
? GridViewSizing.Invisible(options.firstViewVisibleCachedSize)
|
||||
: 0;
|
||||
|
||||
this._addView(view, size, [0]);
|
||||
if (!(view instanceof GridView)) {
|
||||
this._addView(view, size, [0]);
|
||||
}
|
||||
}
|
||||
|
||||
style(styles: IGridStyles): void {
|
||||
@@ -469,12 +479,6 @@ export interface IViewDeserializer<T extends ISerializableView> {
|
||||
fromJSON(json: any): T;
|
||||
}
|
||||
|
||||
interface InitialLayoutContext<T extends ISerializableView> {
|
||||
width: number;
|
||||
height: number;
|
||||
root: GridBranchNode<T>;
|
||||
}
|
||||
|
||||
export interface ISerializedLeafNode {
|
||||
type: 'leaf';
|
||||
data: any;
|
||||
@@ -567,31 +571,9 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
throw new Error('Invalid JSON: \'height\' property must be a number.');
|
||||
}
|
||||
|
||||
const orientation = json.orientation;
|
||||
const width = json.width;
|
||||
const height = json.height;
|
||||
const box: Box = { top: 0, left: 0, width, height };
|
||||
const gridview = GridView.deserialize(json, deserializer, options);
|
||||
const result = new SerializableGrid<T>(gridview, options);
|
||||
|
||||
const root = SerializableGrid.deserializeNode(json.root, orientation, box, deserializer) as GridBranchNode<T>;
|
||||
const firstLeaf = SerializableGrid.getFirstLeaf(root);
|
||||
|
||||
if (!firstLeaf) {
|
||||
throw new Error('Invalid serialized state, first leaf not found');
|
||||
}
|
||||
|
||||
const layoutController = new LayoutController(false);
|
||||
options = { ...options, layoutController };
|
||||
|
||||
if (typeof firstLeaf.cachedVisibleSize === 'number') {
|
||||
options = { ...options, firstViewVisibleCachedSize: firstLeaf.cachedVisibleSize };
|
||||
}
|
||||
|
||||
const result = new SerializableGrid<T>(firstLeaf.view, options);
|
||||
result.orientation = orientation;
|
||||
result.restoreViews(firstLeaf.view, orientation, root);
|
||||
result.initialLayoutContext = { width, height, root };
|
||||
|
||||
layoutController.isLayoutEnabled = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -599,7 +581,7 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
* Useful information in order to proportionally restore view sizes
|
||||
* upon the very first layout call.
|
||||
*/
|
||||
private initialLayoutContext: InitialLayoutContext<T> | undefined;
|
||||
private initialLayoutContext: boolean = true;
|
||||
|
||||
serialize(): ISerializedGrid {
|
||||
return {
|
||||
@@ -614,65 +596,8 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
super.layout(width, height);
|
||||
|
||||
if (this.initialLayoutContext) {
|
||||
const widthScale = width / this.initialLayoutContext.width;
|
||||
const heightScale = height / this.initialLayoutContext.height;
|
||||
|
||||
this.restoreViewsSize([], this.initialLayoutContext.root, this.orientation, widthScale, heightScale);
|
||||
this.initialLayoutContext = undefined;
|
||||
|
||||
this.gridview.trySet2x2();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively restores views which were just deserialized.
|
||||
*/
|
||||
private restoreViews(referenceView: T, orientation: Orientation, node: GridNode<T>): void {
|
||||
if (!isGridBranchNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const direction = orientation === Orientation.VERTICAL ? Direction.Down : Direction.Right;
|
||||
const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c));
|
||||
|
||||
for (let i = 1; i < firstLeaves.length; i++) {
|
||||
const node = firstLeaves[i];
|
||||
const size: number | InvisibleSizing = typeof node.cachedVisibleSize === 'number'
|
||||
? GridViewSizing.Invisible(node.cachedVisibleSize)
|
||||
: (orientation === Orientation.VERTICAL ? node.box.height : node.box.width);
|
||||
this.addView(node.view, size, referenceView, direction);
|
||||
referenceView = node.view;
|
||||
}
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively restores view sizes.
|
||||
* This should be called only after the very first layout call.
|
||||
*/
|
||||
private restoreViewsSize(location: number[], node: GridNode<T>, orientation: Orientation, widthScale: number, heightScale: number): void {
|
||||
if (!isGridBranchNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scale = orientation === Orientation.VERTICAL ? heightScale : widthScale;
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
const child = node.children[i];
|
||||
const childLocation = [...location, i];
|
||||
|
||||
if (i < node.children.length - 1) {
|
||||
const size = orientation === Orientation.VERTICAL
|
||||
? { height: Math.floor(child.box.height * scale) }
|
||||
: { width: Math.floor(child.box.width * scale) };
|
||||
|
||||
this.gridview.resizeView(childLocation, size);
|
||||
}
|
||||
|
||||
this.restoreViewsSize(childLocation, child, orthogonal(orientation), widthScale, heightScale);
|
||||
this.initialLayoutContext = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,36 @@ export interface IView {
|
||||
setVisible?(visible: boolean): void;
|
||||
}
|
||||
|
||||
export interface ISerializableView extends IView {
|
||||
toJSON(): object;
|
||||
}
|
||||
|
||||
export interface IViewDeserializer<T extends ISerializableView> {
|
||||
fromJSON(json: any): T;
|
||||
}
|
||||
|
||||
export interface ISerializedLeafNode {
|
||||
type: 'leaf';
|
||||
data: any;
|
||||
size: number;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
export interface ISerializedBranchNode {
|
||||
type: 'branch';
|
||||
data: ISerializedNode[];
|
||||
size: number;
|
||||
}
|
||||
|
||||
export type ISerializedNode = ISerializedLeafNode | ISerializedBranchNode;
|
||||
|
||||
export interface ISerializedGridView {
|
||||
root: ISerializedNode;
|
||||
orientation: Orientation;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function orthogonal(orientation: Orientation): Orientation {
|
||||
return orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;
|
||||
}
|
||||
@@ -179,18 +209,49 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
styles: IGridViewStyles,
|
||||
readonly proportionalLayout: boolean,
|
||||
size: number = 0,
|
||||
orthogonalSize: number = 0
|
||||
orthogonalSize: number = 0,
|
||||
childDescriptors?: INodeDescriptor[]
|
||||
) {
|
||||
this._styles = styles;
|
||||
this._size = size;
|
||||
this._orthogonalSize = orthogonalSize;
|
||||
|
||||
this.element = $('.monaco-grid-branch-node');
|
||||
this.splitview = new SplitView(this.element, { orientation, styles, proportionalLayout });
|
||||
this.splitview.layout(size, orthogonalSize);
|
||||
|
||||
if (!childDescriptors) {
|
||||
// Normal behavior, we have no children yet, just set up the splitview
|
||||
this.splitview = new SplitView(this.element, { orientation, styles, proportionalLayout });
|
||||
this.splitview.layout(size, orthogonalSize);
|
||||
} else {
|
||||
// Reconstruction behavior, we want to reconstruct a splitview
|
||||
const descriptor = {
|
||||
views: childDescriptors.map(childDescriptor => {
|
||||
return {
|
||||
view: childDescriptor.node,
|
||||
size: childDescriptor.node.size,
|
||||
visible: childDescriptor.node instanceof LeafNode && childDescriptor.visible !== undefined ? childDescriptor.visible : true
|
||||
};
|
||||
}),
|
||||
size: this.orthogonalSize
|
||||
};
|
||||
|
||||
const options = { proportionalLayout, orientation, styles };
|
||||
|
||||
this.children = childDescriptors.map(c => c.node);
|
||||
this.splitview = new SplitView(this.element, { ...options, descriptor });
|
||||
|
||||
this.children.forEach((node, index) => {
|
||||
// Set up orthogonal sashes for children
|
||||
node.orthogonalStartSash = this.splitview.sashes[index - 1];
|
||||
node.orthogonalEndSash = this.splitview.sashes[index];
|
||||
});
|
||||
}
|
||||
|
||||
const onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]);
|
||||
this.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset);
|
||||
|
||||
const onDidChildrenSashReset = Event.any(...this.children.map((c, i) => Event.map(c.onDidSashReset, location => [i, ...location])));
|
||||
this.childrenSashResetDisposable = onDidChildrenSashReset(this._onDidSashReset.fire, this._onDidSashReset);
|
||||
}
|
||||
|
||||
style(styles: IGridViewStyles): void {
|
||||
@@ -226,7 +287,7 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
addChild(node: Node, size: number | Sizing, index: number): void {
|
||||
addChild(node: Node, size: number | Sizing, index: number, skipLayout?: boolean): void {
|
||||
if (index < 0 || index > this.children.length) {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
@@ -484,9 +545,11 @@ class LeafNode implements ISplitView, IDisposable {
|
||||
readonly view: IView,
|
||||
readonly orientation: Orientation,
|
||||
readonly layoutController: ILayoutController,
|
||||
orthogonalSize: number
|
||||
orthogonalSize: number,
|
||||
size: number = 0
|
||||
) {
|
||||
this._orthogonalSize = orthogonalSize;
|
||||
this._size = size;
|
||||
|
||||
this._onDidViewChange = Event.map(this.view.onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height));
|
||||
this.onDidChange = Event.any(this._onDidViewChange, this._onDidSetLinkedNode.event, this._onDidLinkedWidthNodeChange.event, this._onDidLinkedHeightNodeChange.event);
|
||||
@@ -577,6 +640,11 @@ class LeafNode implements ISplitView, IDisposable {
|
||||
|
||||
type Node = BranchNode | LeafNode;
|
||||
|
||||
export interface INodeDescriptor {
|
||||
node: Node;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T {
|
||||
if (node instanceof BranchNode) {
|
||||
const result = new BranchNode(orthogonal(node.orientation), node.layoutController, node.styles, node.proportionalLayout, size, orthogonalSize);
|
||||
@@ -680,6 +748,18 @@ export class GridView implements IDisposable {
|
||||
this.root = new BranchNode(Orientation.VERTICAL, this.layoutController, this.styles, this.proportionalLayout);
|
||||
}
|
||||
|
||||
getViewMap(map: Map<IView, HTMLElement>, node?: Node): void {
|
||||
if (!node) {
|
||||
node = this.root;
|
||||
}
|
||||
|
||||
if (node instanceof BranchNode) {
|
||||
node.children.forEach(child => this.getViewMap(map, child));
|
||||
} else {
|
||||
map.set(node.view, node.element);
|
||||
}
|
||||
}
|
||||
|
||||
style(styles: IGridViewStyles): void {
|
||||
this.styles = styles;
|
||||
this.root.style(styles);
|
||||
@@ -953,6 +1033,47 @@ export class GridView implements IDisposable {
|
||||
return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height });
|
||||
}
|
||||
|
||||
static deserialize<T extends ISerializableView>(json: ISerializedGridView, deserializer: IViewDeserializer<T>, options: IGridViewOptions = {}): GridView {
|
||||
if (typeof json.orientation !== 'number') {
|
||||
throw new Error('Invalid JSON: \'orientation\' property must be a number.');
|
||||
} else if (typeof json.width !== 'number') {
|
||||
throw new Error('Invalid JSON: \'width\' property must be a number.');
|
||||
} else if (typeof json.height !== 'number') {
|
||||
throw new Error('Invalid JSON: \'height\' property must be a number.');
|
||||
}
|
||||
|
||||
const orientation = json.orientation;
|
||||
const height = json.height;
|
||||
|
||||
const result = new GridView(options);
|
||||
result._deserialize(json.root as ISerializedBranchNode, orientation, deserializer, height);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _deserialize(root: ISerializedBranchNode, orientation: Orientation, deserializer: IViewDeserializer<ISerializableView>, orthogonalSize: number): void {
|
||||
this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize) as BranchNode;
|
||||
}
|
||||
|
||||
private _deserializeNode(node: ISerializedNode, orientation: Orientation, deserializer: IViewDeserializer<ISerializableView>, orthogonalSize: number): Node {
|
||||
let result: Node;
|
||||
if (node.type === 'branch') {
|
||||
const serializedChildren = node.data as ISerializedNode[];
|
||||
const children = serializedChildren.map(serializedChild => {
|
||||
return {
|
||||
node: this._deserializeNode(serializedChild, orthogonal(orientation), deserializer, node.size),
|
||||
visible: (serializedChild as { visible?: boolean }).visible
|
||||
} as INodeDescriptor;
|
||||
});
|
||||
|
||||
result = new BranchNode(orientation, this.layoutController, this.styles, this.proportionalLayout, node.size, orthogonalSize, children);
|
||||
} else {
|
||||
result = new LeafNode(deserializer.fromJSON(node.data), orientation, this.layoutController, orthogonalSize, node.size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _getViews(node: Node, orientation: Orientation, box: Box, cachedVisibleSize?: number): GridNode {
|
||||
if (node instanceof LeafNode) {
|
||||
return { view: node.view, box, cachedVisibleSize };
|
||||
|
||||
Reference in New Issue
Block a user