mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from master
This commit is contained in:
@@ -3,18 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./gridview';
|
||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { tail2 as tail } from 'vs/base/common/arrays';
|
||||
import { tail2 as tail, equals } from 'vs/base/common/arrays';
|
||||
import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles } from './gridview';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export { Orientation } from './gridview';
|
||||
|
||||
export enum Direction {
|
||||
export const enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
@@ -141,10 +139,15 @@ export function getRelativeLocation(rootOrientation: Orientation, location: numb
|
||||
|
||||
function indexInParent(element: HTMLElement): number {
|
||||
const parentElement = element.parentElement;
|
||||
|
||||
if (!parentElement) {
|
||||
throw new Error('Invalid grid element');
|
||||
}
|
||||
|
||||
let el = parentElement.firstElementChild;
|
||||
let index = 0;
|
||||
|
||||
while (el !== element && el !== parentElement.lastElementChild) {
|
||||
while (el !== element && el !== parentElement.lastElementChild && el) {
|
||||
el = el.nextElementSibling;
|
||||
index++;
|
||||
}
|
||||
@@ -159,16 +162,22 @@ function indexInParent(element: HTMLElement): number {
|
||||
* This will break as soon as DOM structures of the Splitview or Gridview change.
|
||||
*/
|
||||
function getGridLocation(element: HTMLElement): number[] {
|
||||
if (/\bmonaco-grid-view\b/.test(element.parentElement.className)) {
|
||||
const parentElement = element.parentElement;
|
||||
|
||||
if (!parentElement) {
|
||||
throw new Error('Invalid grid element');
|
||||
}
|
||||
|
||||
if (/\bmonaco-grid-view\b/.test(parentElement.className)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const index = indexInParent(element.parentElement);
|
||||
const ancestor = element.parentElement.parentElement.parentElement.parentElement;
|
||||
const index = indexInParent(parentElement);
|
||||
const ancestor = parentElement.parentElement!.parentElement!.parentElement!;
|
||||
return [...getGridLocation(ancestor), index];
|
||||
}
|
||||
|
||||
export enum Sizing {
|
||||
export const enum Sizing {
|
||||
Distribute = 'distribute',
|
||||
Split = 'split'
|
||||
}
|
||||
@@ -195,7 +204,7 @@ export class Grid<T extends IView> implements IDisposable {
|
||||
get minimumHeight(): number { return this.gridview.minimumHeight; }
|
||||
get maximumWidth(): number { return this.gridview.maximumWidth; }
|
||||
get maximumHeight(): number { return this.gridview.maximumHeight; }
|
||||
get onDidChange(): Event<{ width: number; height: number; }> { return this.gridview.onDidChange; }
|
||||
get onDidChange(): Event<{ width: number; height: number; } | undefined> { return this.gridview.onDidChange; }
|
||||
|
||||
get element(): HTMLElement { return this.gridview.element; }
|
||||
|
||||
@@ -256,15 +265,27 @@ export class Grid<T extends IView> implements IDisposable {
|
||||
throw new Error('Can\'t remove last view');
|
||||
}
|
||||
|
||||
if (!this.views.has(view)) {
|
||||
throw new Error('View not found');
|
||||
}
|
||||
|
||||
const location = this.getViewLocation(view);
|
||||
this.gridview.removeView(location, sizing === Sizing.Distribute ? GridViewSizing.Distribute : undefined);
|
||||
this.views.delete(view);
|
||||
}
|
||||
|
||||
moveView(view: T, sizing: number | Sizing, referenceView: T, direction: Direction): void {
|
||||
const sourceLocation = this.getViewLocation(view);
|
||||
const [sourceParentLocation, from] = tail(sourceLocation);
|
||||
|
||||
const referenceLocation = this.getViewLocation(referenceView);
|
||||
const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, direction);
|
||||
const [targetParentLocation, to] = tail(targetLocation);
|
||||
|
||||
if (equals(sourceParentLocation, targetParentLocation)) {
|
||||
this.gridview.moveView(sourceParentLocation, from, to);
|
||||
} else {
|
||||
this.removeView(view, typeof sizing === 'number' ? undefined : sizing);
|
||||
this.addView(view, sizing, referenceView, direction);
|
||||
}
|
||||
}
|
||||
|
||||
swapViews(from: T, to: T): void {
|
||||
const fromLocation = this.getViewLocation(from);
|
||||
const toLocation = this.getViewLocation(to);
|
||||
@@ -358,7 +379,7 @@ export interface ISerializableView extends IView {
|
||||
}
|
||||
|
||||
export interface IViewDeserializer<T extends ISerializableView> {
|
||||
fromJSON(json: object): T;
|
||||
fromJSON(json: object | null): T;
|
||||
}
|
||||
|
||||
interface InitialLayoutContext<T extends ISerializableView> {
|
||||
@@ -369,7 +390,7 @@ interface InitialLayoutContext<T extends ISerializableView> {
|
||||
|
||||
export interface ISerializedLeafNode {
|
||||
type: 'leaf';
|
||||
data: object;
|
||||
data: object | null;
|
||||
size: number;
|
||||
}
|
||||
|
||||
@@ -405,18 +426,15 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
|
||||
const type = json.type;
|
||||
const data = json.data;
|
||||
|
||||
if (type === 'branch') {
|
||||
if (!Array.isArray(data)) {
|
||||
if (json.type === 'branch') {
|
||||
if (!Array.isArray(json.data)) {
|
||||
throw new Error('Invalid JSON: \'data\' property of branch must be an array.');
|
||||
}
|
||||
|
||||
const children: GridNode<T>[] = [];
|
||||
let offset = 0;
|
||||
|
||||
for (const child of data) {
|
||||
for (const child of json.data) {
|
||||
if (typeof child.size !== 'number') {
|
||||
throw new Error('Invalid JSON: \'size\' property of node must be a number.');
|
||||
}
|
||||
@@ -431,8 +449,8 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
|
||||
return { children, box };
|
||||
|
||||
} else if (type === 'leaf') {
|
||||
const view = deserializer.fromJSON(data) as T;
|
||||
} else if (json.type === 'leaf') {
|
||||
const view = deserializer.fromJSON(json.data) as T;
|
||||
return { view, box };
|
||||
}
|
||||
|
||||
@@ -517,13 +535,13 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c));
|
||||
|
||||
for (let i = 1; i < firstLeaves.length; i++) {
|
||||
const size = orientation === Orientation.VERTICAL ? firstLeaves[i].box.height : firstLeaves[i].box.width;
|
||||
this.addView(firstLeaves[i].view, size, referenceView, direction);
|
||||
referenceView = firstLeaves[i].view;
|
||||
const size = orientation === Orientation.VERTICAL ? firstLeaves[i]!.box.height : firstLeaves[i]!.box.width;
|
||||
this.addView(firstLeaves[i]!.view, size, referenceView, direction);
|
||||
referenceView = firstLeaves[i]!.view;
|
||||
}
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]);
|
||||
this.restoreViews(firstLeaves[i]!.view, orthogonal(orientation), node.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,10 +619,10 @@ function getDimensions(node: ISerializedNode, orientation: Orientation): { width
|
||||
|
||||
if (orientation === Orientation.VERTICAL) {
|
||||
const width = node.size || (childrenDimensions.length === 0 ? undefined : Math.max(...childrenDimensions.map(d => d.width || 0)));
|
||||
const height = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + d.height, 0);
|
||||
const height = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + (d.height || 0), 0);
|
||||
return { width, height };
|
||||
} else {
|
||||
const width = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + d.width, 0);
|
||||
const width = childrenDimensions.length === 0 ? undefined : childrenDimensions.reduce((r, d) => r + (d.width || 0), 0);
|
||||
const height = node.size || (childrenDimensions.length === 0 ? undefined : Math.max(...childrenDimensions.map(d => d.height || 0)));
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
@@ -3,18 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./gridview';
|
||||
import { Event, anyEvent, Emitter, mapEvent, Relay } from 'vs/base/common/event';
|
||||
import { Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { SplitView, IView as ISplitView, Sizing, ISplitViewStyles } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { SplitView, IView as ISplitView, Sizing, LayoutPriority, ISplitViewStyles } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { tail2 as tail } from 'vs/base/common/arrays';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
|
||||
export { Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
export { Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
|
||||
export { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
|
||||
export interface IView {
|
||||
@@ -24,6 +22,8 @@ export interface IView {
|
||||
readonly minimumHeight: number;
|
||||
readonly maximumHeight: number;
|
||||
readonly onDidChange: Event<{ width: number; height: number; }>;
|
||||
readonly priority?: LayoutPriority;
|
||||
readonly snapSize?: number;
|
||||
layout(width: number, height: number): void;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ const defaultStyles: IGridViewStyles = {
|
||||
|
||||
export interface IGridViewOptions {
|
||||
styles?: IGridViewStyles;
|
||||
proportionalLayout?: boolean; // default true
|
||||
}
|
||||
|
||||
class BranchNode implements ISplitView, IDisposable {
|
||||
@@ -137,6 +138,7 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
constructor(
|
||||
readonly orientation: Orientation,
|
||||
styles: IGridViewStyles,
|
||||
readonly proportionalLayout: boolean,
|
||||
size: number = 0,
|
||||
orthogonalSize: number = 0
|
||||
) {
|
||||
@@ -181,9 +183,14 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
|
||||
const first = index === 0;
|
||||
const last = index === this.splitview.length;
|
||||
this.splitview.addView(node, size, index);
|
||||
this._addChild(node, index);
|
||||
this.onDidChildrenChange();
|
||||
}
|
||||
|
||||
private _addChild(node: Node, index: number): void {
|
||||
const first = index === 0;
|
||||
const last = index === this.children.length;
|
||||
this.children.splice(index, 0, node);
|
||||
node.orthogonalStartSash = this.splitview.sashes[index - 1];
|
||||
node.orthogonalEndSash = this.splitview.sashes[index];
|
||||
@@ -195,8 +202,6 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
if (!last) {
|
||||
this.children[index + 1].orthogonalStartSash = this.splitview.sashes[index];
|
||||
}
|
||||
|
||||
this.onDidChildrenChange();
|
||||
}
|
||||
|
||||
removeChild(index: number, sizing?: Sizing): void {
|
||||
@@ -204,10 +209,15 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
|
||||
const first = index === 0;
|
||||
const last = index === this.splitview.length - 1;
|
||||
this.splitview.removeView(index, sizing);
|
||||
this.children.splice(index, 1);
|
||||
this._removeChild(index);
|
||||
this.onDidChildrenChange();
|
||||
}
|
||||
|
||||
private _removeChild(index: number): Node {
|
||||
const first = index === 0;
|
||||
const last = index === this.children.length - 1;
|
||||
const [child] = this.children.splice(index, 1);
|
||||
|
||||
if (!first) {
|
||||
this.children[index - 1].orthogonalEndSash = this.splitview.sashes[index - 1];
|
||||
@@ -217,7 +227,30 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
this.children[index].orthogonalStartSash = this.splitview.sashes[Math.max(index - 1, 0)];
|
||||
}
|
||||
|
||||
this.onDidChildrenChange();
|
||||
return child;
|
||||
}
|
||||
|
||||
moveChild(from: number, to: number): void {
|
||||
if (from === to) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from < 0 || from >= this.children.length) {
|
||||
throw new Error('Invalid from index');
|
||||
}
|
||||
|
||||
if (to < 0 || to > this.children.length) {
|
||||
throw new Error('Invalid to index');
|
||||
}
|
||||
|
||||
if (from < to) {
|
||||
to--;
|
||||
}
|
||||
|
||||
this.splitview.moveView(from, to);
|
||||
|
||||
const child = this._removeChild(from);
|
||||
this._addChild(child, to);
|
||||
}
|
||||
|
||||
swapChildren(from: number, to: number): void {
|
||||
@@ -332,6 +365,9 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
child.dispose();
|
||||
}
|
||||
|
||||
this._onDidChange.dispose();
|
||||
this._onDidSashReset.dispose();
|
||||
|
||||
this.splitviewSashResetDisposable.dispose();
|
||||
this.childrenSashResetDisposable.dispose();
|
||||
this.childrenChangeDisposable.dispose();
|
||||
@@ -418,6 +454,14 @@ class LeafNode implements ISplitView, IDisposable {
|
||||
return this.orientation === Orientation.HORIZONTAL ? this.maximumHeight : this.maximumWidth;
|
||||
}
|
||||
|
||||
get priority(): LayoutPriority | undefined {
|
||||
return this.view.priority;
|
||||
}
|
||||
|
||||
get snapSize(): number | undefined {
|
||||
return this.view.snapSize;
|
||||
}
|
||||
|
||||
get minimumOrthogonalSize(): number {
|
||||
return this.orientation === Orientation.HORIZONTAL ? this.minimumWidth : this.minimumHeight;
|
||||
}
|
||||
@@ -451,7 +495,7 @@ type Node = BranchNode | LeafNode;
|
||||
|
||||
function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T {
|
||||
if (node instanceof BranchNode) {
|
||||
const result = new BranchNode(orthogonal(node.orientation), node.styles, size, orthogonalSize);
|
||||
const result = new BranchNode(orthogonal(node.orientation), node.styles, node.proportionalLayout, size, orthogonalSize);
|
||||
|
||||
let totalSize = 0;
|
||||
|
||||
@@ -480,6 +524,7 @@ export class GridView implements IDisposable {
|
||||
|
||||
readonly element: HTMLElement;
|
||||
private styles: IGridViewStyles;
|
||||
private proportionalLayout: boolean;
|
||||
|
||||
private _root: BranchNode;
|
||||
private onDidSashResetRelay = new Relay<number[]>();
|
||||
@@ -528,13 +573,14 @@ export class GridView implements IDisposable {
|
||||
get maximumWidth(): number { return this.root.maximumHeight; }
|
||||
get maximumHeight(): number { return this.root.maximumHeight; }
|
||||
|
||||
private _onDidChange = new Relay<{ width: number; height: number; }>();
|
||||
private _onDidChange = new Relay<{ width: number; height: number; } | undefined>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
constructor(options: IGridViewOptions = {}) {
|
||||
this.element = $('.monaco-grid-view');
|
||||
this.styles = options.styles || defaultStyles;
|
||||
this.root = new BranchNode(Orientation.VERTICAL, this.styles);
|
||||
this.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true;
|
||||
this.root = new BranchNode(Orientation.VERTICAL, this.styles, this.proportionalLayout);
|
||||
}
|
||||
|
||||
style(styles: IGridViewStyles): void {
|
||||
@@ -564,7 +610,7 @@ export class GridView implements IDisposable {
|
||||
const [, parentIndex] = tail(rest);
|
||||
grandParent.removeChild(parentIndex);
|
||||
|
||||
const newParent = new BranchNode(parent.orientation, this.styles, parent.size, parent.orthogonalSize);
|
||||
const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize);
|
||||
grandParent.addChild(newParent, parent.size, parentIndex);
|
||||
newParent.orthogonalLayout(parent.orthogonalSize);
|
||||
|
||||
@@ -648,6 +694,16 @@ export class GridView implements IDisposable {
|
||||
return node.view;
|
||||
}
|
||||
|
||||
moveView(parentLocation: number[], from: number, to: number): void {
|
||||
const [, parent] = this.getNode(parentLocation);
|
||||
|
||||
if (!(parent instanceof BranchNode)) {
|
||||
throw new Error('Invalid location');
|
||||
}
|
||||
|
||||
parent.moveChild(from, to);
|
||||
}
|
||||
|
||||
swapViews(from: number[], to: number[]): void {
|
||||
const [fromRest, fromIndex] = tail(from);
|
||||
const [, fromParent] = this.getNode(fromRest);
|
||||
|
||||
Reference in New Issue
Block a user