sussudio
Version:
An unofficial VS Code Internal API
581 lines (580 loc) • 20.4 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IBoundarySashes, Orientation, Sash } from "../sash/sash.mjs";
import { DistributeSizing, ISplitViewStyles, IView as ISplitView, LayoutPriority, Sizing } from "../splitview/splitview.mjs";
import { Event } from "../../../common/event.mjs";
import { IDisposable } from "../../../common/lifecycle.mjs";
import "../../../../css!./gridview.mjs";
export { Orientation } from "../sash/sash.mjs";
export { LayoutPriority, Sizing } from "../splitview/splitview.mjs";
export interface IGridViewStyles extends ISplitViewStyles {
}
export interface IViewSize {
readonly width: number;
readonly height: number;
}
interface IRelativeBoundarySashes {
readonly start?: Sash;
readonly end?: Sash;
readonly orthogonalStart?: Sash;
readonly orthogonalEnd?: Sash;
}
/**
* The interface to implement for views within a {@link GridView}.
*/
export interface IView {
/**
* The DOM element for this view.
*/
readonly element: HTMLElement;
/**
* A minimum width for this view.
*
* @remarks If none, set it to `0`.
*/
readonly minimumWidth: number;
/**
* A minimum width for this view.
*
* @remarks If none, set it to `Number.POSITIVE_INFINITY`.
*/
readonly maximumWidth: number;
/**
* A minimum height for this view.
*
* @remarks If none, set it to `0`.
*/
readonly minimumHeight: number;
/**
* A minimum height for this view.
*
* @remarks If none, set it to `Number.POSITIVE_INFINITY`.
*/
readonly maximumHeight: number;
/**
* The priority of the view when the {@link GridView} layout algorithm
* runs. Views with higher priority will be resized first.
*
* @remarks Only used when `proportionalLayout` is false.
*/
readonly priority?: LayoutPriority;
/**
* If the {@link GridView} supports proportional layout,
* this property allows for finer control over the proportional layout algorithm, per view.
*
* @defaultValue `true`
*/
readonly proportionalLayout?: boolean;
/**
* Whether the view will snap whenever the user reaches its minimum size or
* attempts to grow it beyond the minimum size.
*
* @defaultValue `false`
*/
readonly snap?: boolean;
/**
* View instances are supposed to fire this event whenever any of the constraint
* properties have changed:
*
* - {@link IView.minimumWidth}
* - {@link IView.maximumWidth}
* - {@link IView.minimumHeight}
* - {@link IView.maximumHeight}
* - {@link IView.priority}
* - {@link IView.snap}
*
* The {@link GridView} will relayout whenever that happens. The event can
* optionally emit the view's preferred size for that relayout.
*/
readonly onDidChange: Event<IViewSize | undefined>;
/**
* This will be called by the {@link GridView} during layout. A view meant to
* pass along the layout information down to its descendants.
*/
layout(width: number, height: number, top: number, left: number): void;
/**
* This will be called by the {@link GridView} whenever this view is made
* visible or hidden.
*
* @param visible Whether the view becomes visible.
*/
setVisible?(visible: boolean): void;
/**
* This will be called by the {@link GridView} whenever this view is on
* an edge of the grid and the grid's
* {@link GridView.boundarySashes boundary sashes} change.
*/
setBoundarySashes?(sashes: IBoundarySashes): 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 declare function orthogonal(orientation: Orientation): Orientation;
export interface Box {
readonly top: number;
readonly left: number;
readonly width: number;
readonly height: number;
}
export interface GridLeafNode {
readonly view: IView;
readonly box: Box;
readonly cachedVisibleSize: number | undefined;
}
export interface GridBranchNode {
readonly children: GridNode[];
readonly box: Box;
}
export type GridNode = GridLeafNode | GridBranchNode;
export declare function isGridBranchNode(node: GridNode): node is GridBranchNode;
declare class LayoutController {
isLayoutEnabled: boolean;
constructor(isLayoutEnabled: boolean);
}
export interface IGridViewOptions {
/**
* Styles overriding the {@link defaultStyles default ones}.
*/
readonly styles?: IGridViewStyles;
/**
* Resize each view proportionally when resizing the {@link GridView}.
*
* @defaultValue `true`
*/
readonly proportionalLayout?: boolean;
}
interface ILayoutContext {
readonly orthogonalSize: number;
readonly absoluteOffset: number;
readonly absoluteOrthogonalOffset: number;
readonly absoluteSize: number;
readonly absoluteOrthogonalSize: number;
}
declare class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
readonly orientation: Orientation;
readonly layoutController: LayoutController;
readonly splitviewProportionalLayout: boolean;
readonly element: HTMLElement;
readonly children: Node[];
private splitview;
private _size;
get size(): number;
private _orthogonalSize;
get orthogonalSize(): number;
private _absoluteOffset;
get absoluteOffset(): number;
private _absoluteOrthogonalOffset;
get absoluteOrthogonalOffset(): number;
private absoluteOrthogonalSize;
private _styles;
get styles(): IGridViewStyles;
get width(): number;
get height(): number;
get top(): number;
get left(): number;
get minimumSize(): number;
get maximumSize(): number;
get priority(): LayoutPriority;
get proportionalLayout(): boolean;
get minimumOrthogonalSize(): number;
get maximumOrthogonalSize(): number;
get minimumWidth(): number;
get minimumHeight(): number;
get maximumWidth(): number;
get maximumHeight(): number;
private readonly _onDidChange;
readonly onDidChange: Event<number | undefined>;
private _onDidScroll;
private onDidScrollDisposable;
readonly onDidScroll: Event<void>;
private childrenChangeDisposable;
private readonly _onDidSashReset;
readonly onDidSashReset: Event<GridLocation>;
private splitviewSashResetDisposable;
private childrenSashResetDisposable;
private _boundarySashes;
get boundarySashes(): IRelativeBoundarySashes;
set boundarySashes(boundarySashes: IRelativeBoundarySashes);
private _edgeSnapping;
get edgeSnapping(): boolean;
set edgeSnapping(edgeSnapping: boolean);
constructor(orientation: Orientation, layoutController: LayoutController, styles: IGridViewStyles, splitviewProportionalLayout: boolean, size?: number, orthogonalSize?: number, edgeSnapping?: boolean, childDescriptors?: INodeDescriptor[]);
style(styles: IGridViewStyles): void;
layout(size: number, offset: number, ctx: ILayoutContext | undefined): void;
setVisible(visible: boolean): void;
addChild(node: Node, size: number | Sizing, index: number, skipLayout?: boolean): void;
private _addChild;
removeChild(index: number, sizing?: Sizing): void;
private _removeChild;
moveChild(from: number, to: number): void;
swapChildren(from: number, to: number): void;
resizeChild(index: number, size: number): void;
isChildSizeMaximized(index: number): boolean;
distributeViewSizes(recursive?: boolean): void;
getChildSize(index: number): number;
isChildVisible(index: number): boolean;
setChildVisible(index: number, visible: boolean): void;
getChildCachedVisibleSize(index: number): number | undefined;
private onDidChildrenChange;
private updateChildrenEvents;
trySet2x2(other: BranchNode): IDisposable;
private updateSplitviewEdgeSnappingEnablement;
dispose(): void;
}
declare class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
readonly view: IView;
readonly orientation: Orientation;
readonly layoutController: LayoutController;
private _size;
get size(): number;
private _orthogonalSize;
get orthogonalSize(): number;
private absoluteOffset;
private absoluteOrthogonalOffset;
readonly onDidScroll: Event<void>;
readonly onDidSashReset: Event<GridLocation>;
private _onDidLinkedWidthNodeChange;
private _linkedWidthNode;
get linkedWidthNode(): LeafNode | undefined;
set linkedWidthNode(node: LeafNode | undefined);
private _onDidLinkedHeightNodeChange;
private _linkedHeightNode;
get linkedHeightNode(): LeafNode | undefined;
set linkedHeightNode(node: LeafNode | undefined);
private readonly _onDidSetLinkedNode;
private _onDidViewChange;
readonly onDidChange: Event<number | undefined>;
private disposables;
constructor(view: IView, orientation: Orientation, layoutController: LayoutController, orthogonalSize: number, size?: number);
get width(): number;
get height(): number;
get top(): number;
get left(): number;
get element(): HTMLElement;
private get minimumWidth();
private get maximumWidth();
private get minimumHeight();
private get maximumHeight();
get minimumSize(): number;
get maximumSize(): number;
get priority(): LayoutPriority | undefined;
get proportionalLayout(): boolean;
get snap(): boolean | undefined;
get minimumOrthogonalSize(): number;
get maximumOrthogonalSize(): number;
private _boundarySashes;
get boundarySashes(): IRelativeBoundarySashes;
set boundarySashes(boundarySashes: IRelativeBoundarySashes);
layout(size: number, offset: number, ctx: ILayoutContext | undefined): void;
private cachedWidth;
private cachedHeight;
private cachedTop;
private cachedLeft;
private _layout;
setVisible(visible: boolean): void;
dispose(): void;
}
type Node = BranchNode | LeafNode;
export interface INodeDescriptor {
node: Node;
visible?: boolean;
}
/**
* The location of a {@link IView view} within a {@link GridView}.
*
* A GridView is a tree composition of multiple {@link SplitView} instances, orthogonal
* between one another. Here's an example:
*
* ```
* +-----+---------------+
* | A | B |
* +-----+---------+-----+
* | C | |
* +---------------+ D |
* | E | |
* +---------------+-----+
* ```
*
* The above grid's tree structure is:
*
* ```
* Vertical SplitView
* +-Horizontal SplitView
* | +-A
* | +-B
* +- Horizontal SplitView
* +-Vertical SplitView
* | +-C
* | +-E
* +-D
* ```
*
* So, {@link IView views} within a {@link GridView} can be referenced by
* a sequence of indexes, each index referencing each SplitView. Here are
* each view's locations, from the example above:
*
* - `A`: `[0,0]`
* - `B`: `[0,1]`
* - `C`: `[1,0,0]`
* - `D`: `[1,1]`
* - `E`: `[1,0,1]`
*/
export type GridLocation = number[];
/**
* The {@link GridView} is the UI component which implements a two dimensional
* flex-like layout algorithm for a collection of {@link IView} instances, which
* are mostly HTMLElement instances with size constraints. A {@link GridView} is a
* tree composition of multiple {@link SplitView} instances, orthogonal between
* one another. It will respect view's size contraints, just like the SplitView.
*
* It has a low-level index based API, allowing for fine grain performant operations.
* Look into the {@link Grid} widget for a higher-level API.
*
* Features:
* - flex-like layout algorithm
* - snap support
* - corner sash support
* - Alt key modifier behavior, macOS style
* - layout (de)serialization
*/
export declare class GridView implements IDisposable {
/**
* The DOM element for this view.
*/
readonly element: HTMLElement;
private styles;
private proportionalLayout;
private _root;
private onDidSashResetRelay;
private _onDidScroll;
private _onDidChange;
private _boundarySashes;
/**
* The layout controller makes sure layout only propagates
* to the views after the very first call to {@link GridView.layout}.
*/
private layoutController;
private disposable2x2;
private get root();
private set root(value);
/**
* Fires whenever the user double clicks a {@link Sash sash}.
*/
readonly onDidSashReset: Event<GridLocation>;
/**
* Fires whenever the user scrolls a {@link SplitView} within
* the grid.
*/
readonly onDidScroll: Event<void>;
/**
* Fires whenever a view within the grid changes its size constraints.
*/
readonly onDidChange: Event<IViewSize | undefined>;
/**
* The width of the grid.
*/
get width(): number;
/**
* The height of the grid.
*/
get height(): number;
/**
* The minimum width of the grid.
*/
get minimumWidth(): number;
/**
* The minimum height of the grid.
*/
get minimumHeight(): number;
/**
* The maximum width of the grid.
*/
get maximumWidth(): number;
/**
* The maximum height of the grid.
*/
get maximumHeight(): number;
get orientation(): Orientation;
get boundarySashes(): IBoundarySashes;
/**
* The orientation of the grid. Matches the orientation of the root
* {@link SplitView} in the grid's tree model.
*/
set orientation(orientation: Orientation);
/**
* A collection of sashes perpendicular to each edge of the grid.
* Corner sashes will be created for each intersection.
*/
set boundarySashes(boundarySashes: IBoundarySashes);
/**
* Enable/disable edge snapping across all grid views.
*/
set edgeSnapping(edgeSnapping: boolean);
/**
* Create a new {@link GridView} instance.
*
* @remarks It's the caller's responsibility to append the
* {@link GridView.element} to the page's DOM.
*/
constructor(options?: IGridViewOptions);
style(styles: IGridViewStyles): void;
/**
* Layout the {@link GridView}.
*
* Optionally provide a `top` and `left` positions, those will propagate
* as an origin for positions passed to {@link IView.layout}.
*
* @param width The width of the {@link GridView}.
* @param height The height of the {@link GridView}.
* @param top Optional, the top location of the {@link GridView}.
* @param left Optional, the left location of the {@link GridView}.
*/
layout(width: number, height: number, top?: number, left?: number): void;
/**
* Add a {@link IView view} to this {@link GridView}.
*
* @param view The view to add.
* @param size Either a fixed size, or a dynamic {@link Sizing} strategy.
* @param location The {@link GridLocation location} to insert the view on.
*/
addView(view: IView, size: number | Sizing, location: GridLocation): void;
/**
* Remove a {@link IView view} from this {@link GridView}.
*
* @param location The {@link GridLocation location} of the {@link IView view}.
* @param sizing Whether to distribute other {@link IView view}'s sizes.
*/
removeView(location: GridLocation, sizing?: DistributeSizing): IView;
/**
* Move a {@link IView view} within its parent.
*
* @param parentLocation The {@link GridLocation location} of the {@link IView view}'s parent.
* @param from The index of the {@link IView view} to move.
* @param to The index where the {@link IView view} should move to.
*/
moveView(parentLocation: GridLocation, from: number, to: number): void;
/**
* Swap two {@link IView views} within the {@link GridView}.
*
* @param from The {@link GridLocation location} of one view.
* @param to The {@link GridLocation location} of another view.
*/
swapViews(from: GridLocation, to: GridLocation): void;
/**
* Resize a {@link IView view}.
*
* @param location The {@link GridLocation location} of the view.
* @param size The size the view should be. Optionally provide a single dimension.
*/
resizeView(location: GridLocation, size: Partial<IViewSize>): void;
/**
* Get the size of a {@link IView view}.
*
* @param location The {@link GridLocation location} of the view. Provide `undefined` to get
* the size of the grid itself.
*/
getViewSize(location?: GridLocation): IViewSize;
/**
* Get the cached visible size of a {@link IView view}. This was the size
* of the view at the moment it last became hidden.
*
* @param location The {@link GridLocation location} of the view.
*/
getViewCachedVisibleSize(location: GridLocation): number | undefined;
/**
* Maximize the size of a {@link IView view} by collapsing all other views
* to their minimum sizes.
*
* @param location The {@link GridLocation location} of the view.
*/
maximizeViewSize(location: GridLocation): void;
/**
* Returns whether all other {@link IView views} are at their minimum size.
*
* @param location The {@link GridLocation location} of the view.
*/
isViewSizeMaximized(location: GridLocation): boolean;
/**
* Distribute the size among all {@link IView views} within the entire
* grid or within a single {@link SplitView}.
*
* @param location The {@link GridLocation location} of a view containing
* children views, which will have their sizes distributed within the parent
* view's size. Provide `undefined` to recursively distribute all views' sizes
* in the entire grid.
*/
distributeViewSizes(location?: GridLocation): void;
/**
* Returns whether a {@link IView view} is visible.
*
* @param location The {@link GridLocation location} of the view.
*/
isViewVisible(location: GridLocation): boolean;
/**
* Set the visibility state of a {@link IView view}.
*
* @param location The {@link GridLocation location} of the view.
*/
setViewVisible(location: GridLocation, visible: boolean): void;
/**
* Returns a descriptor for the entire grid.
*/
getView(): GridBranchNode;
/**
* Returns a descriptor for a {@link GridLocation subtree} within the
* {@link GridView}.
*
* @param location The {@link GridLocation location} of the root of
* the {@link GridLocation subtree}.
*/
getView(location: GridLocation): GridNode;
/**
* Construct a new {@link GridView} from a JSON object.
*
* @param json The JSON object.
* @param deserializer A deserializer which can revive each view.
* @returns A new {@link GridView} instance.
*/
static deserialize<T extends ISerializableView>(json: ISerializedGridView, deserializer: IViewDeserializer<T>, options?: IGridViewOptions): GridView;
private _deserialize;
private _deserializeNode;
private _getViews;
private getNode;
/**
* Attempt to lock the {@link Sash sashes} in this {@link GridView} so
* the grid behaves as a 2x2 matrix, with a corner sash in the middle.
*
* In case the grid isn't a 2x2 grid _and_ all sashes are not aligned,
* this method is a no-op.
*/
trySet2x2(): void;
/**
* Populate a map with views to DOM nodes.
* @remarks To be used internally only.
*/
getViewMap(map: Map<IView, HTMLElement>, node?: Node): void;
dispose(): void;
}