提交 fdf1a1aa 编写于 作者: J Joao Moreno

wip

上级 7db5f72f
......@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { $ } from 'vs/base/browser/dom';
import { LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
export { Orientation } from './gridview';
export { Orientation, Sizing as GridViewSizing } from './gridview';
export const enum Direction {
Up,
......@@ -317,6 +317,16 @@ export class Grid<T extends IView> extends Disposable {
this.gridview.distributeViewSizes();
}
isViewVisible(view: T): boolean {
const location = this.getViewLocation(view);
return this.gridview.isViewVisible(location);
}
setViewVisible(view: T, visible: boolean): void {
const location = this.getViewLocation(view);
this.gridview.setViewVisible(location, visible);
}
getViews(): GridBranchNode<T> {
return this.gridview.getViews() as GridBranchNode<T>;
}
......@@ -653,7 +663,7 @@ export class View implements IView {
readonly onDidChange: Event<{ width: number; height: number; } | undefined>;
get priority(): LayoutPriority | undefined { return this.view.priority; }
get snapSize(): number | undefined { return this.visible ? this.view.snapSize : undefined; }
get snap(): boolean | undefined { return this.view.snap; }
constructor(private view: IView) {
this.show();
......
......@@ -28,8 +28,9 @@ export interface IView {
readonly maximumHeight: number;
readonly onDidChange: Event<IViewSize | undefined>;
readonly priority?: LayoutPriority;
readonly snapSize?: number;
readonly snap?: boolean;
layout(width: number, height: number, orientation: Orientation): void;
setVisible?(visible: boolean): void;
}
export function orthogonal(orientation: Orientation): Orientation {
......@@ -304,6 +305,22 @@ class BranchNode implements ISplitView, IDisposable {
return this.splitview.getViewSize(index);
}
isChildVisible(index: number): boolean {
if (index < 0 || index >= this.children.length) {
throw new Error('Invalid index');
}
return this.splitview.isViewVisible(index);
}
setChildVisible(index: number, visible: boolean): void {
if (index < 0 || index >= this.children.length) {
throw new Error('Invalid index');
}
this.splitview.setViewVisible(index, visible);
}
private onDidChildrenChange(): void {
const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined);
this.childrenChangeDisposable.dispose();
......@@ -463,8 +480,8 @@ class LeafNode implements ISplitView, IDisposable {
return this.view.priority;
}
get snapSize(): number | undefined {
return this.view.snapSize;
get snap(): boolean | undefined {
return this.view.snap;
}
get minimumOrthogonalSize(): number {
......@@ -810,6 +827,28 @@ export class GridView implements IDisposable {
node.distributeViewSizes();
}
isViewVisible(location: number[]): boolean {
const [rest, index] = tail(location);
const [, parent] = this.getNode(rest);
if (!(parent instanceof BranchNode)) {
throw new Error('Invalid from location');
}
return parent.isChildVisible(index);
}
setViewVisible(location: number[], visible: boolean): void {
const [rest, index] = tail(location);
const [, parent] = this.getNode(rest);
if (!(parent instanceof BranchNode)) {
throw new Error('Invalid from location');
}
parent.setChildVisible(index, visible);
}
getViews(): GridBranchNode {
return this._getViews(this.root, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }) as GridBranchNode;
}
......
......@@ -97,8 +97,10 @@ abstract class ViewItem {
get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; }
get viewMinimumSize(): number { return this.view.minimumSize; }
get maximumSize(): number { return this.visible ? this.view.maximumSize : 0; }
get viewMaximumSize(): number { return this.view.maximumSize; }
get priority(): LayoutPriority | undefined { return this.view.priority; }
get snap(): boolean { return !!this.view.snap; }
......@@ -139,6 +141,11 @@ interface ISashItem {
disposable: IDisposable;
}
interface ISashDragSnapState {
readonly index: number;
readonly limitDelta: number;
}
interface ISashDragState {
index: number;
start: number;
......@@ -147,8 +154,8 @@ interface ISashDragState {
minDelta: number;
maxDelta: number;
alt: boolean;
snapIndex: number | undefined;
snapLimitDelta: number | undefined;
snapBefore: ISashDragSnapState | undefined;
snapAfter: ISashDragSnapState | undefined;
disposable: IDisposable;
}
......@@ -486,55 +493,78 @@ export class SplitView extends Disposable {
}
}
let snapIndex: number | undefined;
let snapLimitDelta: number | undefined;
let snapBefore: ISashDragSnapState | undefined;
let snapAfter: ISashDragSnapState | undefined;
if (!alt) {
const upIndexes = range(index, -1);
const downIndexes = range(index + 1, this.viewItems.length);
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0);
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].viewMaximumSize), 0);
const minDelta = Math.max(minDeltaUp, minDeltaDown);
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp);
const snapBefore = this.viewItems[index].snap;
const snapAfter = this.viewItems[index + 1].snap;
const findSnapIndex = (indexes: number[]): number | undefined => {
// visible views first
for (const index of indexes) {
if (!this.viewItems[index].visible) {
continue;
}
if (snapBefore && snapAfter) {
snapIndex = index + 1 < (this.viewItems.length - index - 1) ? index : index + 1;
} else if (snapBefore) {
snapIndex = index;
} else if (snapAfter) {
snapIndex = index + 1;
}
if (this.viewItems[index].snap) {
return index;
}
}
if (typeof snapIndex === 'number') {
if (this.viewItems[snapIndex].visible) {
snapLimitDelta = snapIndex === index
? minDelta - (this.viewItems[index].viewMinimumSize / 2)
: maxDelta + (this.viewItems[index + 1].viewMinimumSize / 2);
} else {
snapLimitDelta = snapIndex === index
? minDelta + (this.viewItems[index].viewMinimumSize / 2)
: maxDelta - (this.viewItems[index + 1].viewMinimumSize / 2);
// then, hidden views
for (const index of indexes) {
if (!this.viewItems[index].visible && this.viewItems[index].snap) {
return index;
}
}
return undefined;
};
const snapBeforeIndex = findSnapIndex(upIndexes);
if (typeof snapBeforeIndex === 'number') {
const viewItem = this.viewItems[snapBeforeIndex];
const halfSize = Math.floor(viewItem.viewMinimumSize / 2);
snapBefore = {
index: snapBeforeIndex,
limitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize
};
}
const snapAfterIndex = findSnapIndex(downIndexes);
if (typeof snapAfterIndex === 'number') {
const viewItem = this.viewItems[snapAfterIndex];
const halfSize = Math.floor(viewItem.viewMinimumSize / 2);
snapAfter = {
index: snapAfterIndex,
limitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize
};
}
}
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapIndex, snapLimitDelta, disposable };
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapBefore, snapAfter, disposable };
};
resetSashDragState(start, alt);
}
private onSashChange({ current }: ISashEvent): void {
const { index, start, sizes, alt, minDelta, maxDelta, snapIndex, snapLimitDelta } = this.sashDragState;
const { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState;
this.sashDragState.current = current;
const delta = current - start;
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapIndex, snapLimitDelta);
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter);
if (alt) {
const isLastSash = index === this.sashItems.length - 1;
......@@ -645,8 +675,8 @@ export class SplitView extends Disposable {
highPriorityIndexes?: number[],
overloadMinDelta: number = Number.NEGATIVE_INFINITY,
overloadMaxDelta: number = Number.POSITIVE_INFINITY,
snapIndex?: number,
snapLimitDelta?: number
snapBefore?: ISashDragSnapState,
snapAfter?: ISashDragSnapState
): number {
if (index < 0 || index >= this.viewItems.length) {
return 0;
......@@ -682,13 +712,23 @@ export class SplitView extends Disposable {
const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);
if (typeof snapIndex === 'number' && typeof snapLimitDelta === 'number') {
const snapView = this.viewItems[snapIndex];
let snapped = false;
snapView.visible = snapIndex === index
? delta >= snapLimitDelta // up
: delta < snapLimitDelta; // down
if (snapBefore) {
const snapView = this.viewItems[snapBefore.index];
const visible = delta >= snapBefore.limitDelta;
snapped = visible !== snapView.visible;
snapView.visible = visible;
}
if (!snapped && snapAfter) {
const snapView = this.viewItems[snapAfter.index];
const visible = delta < snapAfter.limitDelta;
snapped = visible !== snapView.visible;
snapView.visible = visible;
}
if (snapped) {
return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);
}
......@@ -759,9 +799,15 @@ export class SplitView extends Disposable {
previous = false;
const expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse();
const firstVisibleViewIndex = firstIndex(this.viewItems, viewItem => viewItem.visible);
this.sashItems.forEach((s, i) => {
if (!this.viewItems[i].visible) {
s.sash.state = SashState.Disabled;
if (i === firstVisibleViewIndex - 1) {
s.sash.state = SashState.Minimum;
} else {
s.sash.state = SashState.Disabled;
}
} else {
const min = !(collapsesDown[i] && expandsUp[i + 1]);
const max = !(expandsDown[i] && collapsesUp[i + 1]);
......
......@@ -58,7 +58,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
readonly minimumHeight: number = 77;
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
readonly snapSize: number = 50;
readonly priority: LayoutPriority = LayoutPriority.Low;
//#endregion
......
......@@ -46,7 +46,6 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
readonly minimumHeight: number = 0;
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
readonly snapSize: number = 50;
readonly priority: LayoutPriority = LayoutPriority.Low;
//#endregion
......
......@@ -5,7 +5,7 @@
<title>Splitview</title>
<style>
#container {
width: 400px;
width: 800px;
height: 600px;
border: 1px solid black;
}
......@@ -18,7 +18,7 @@
color: white;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-weight: bold;
font-size: 40px;
font-size: 30px;
}
</style>
</head>
......@@ -31,51 +31,107 @@
<script>
require.config({ baseUrl: '/static' });
require(['vs/base/browser/ui/splitview/splitview', 'vs/base/common/event'], ({ SplitView, Sizing }, { Event }) => {
const buttons = document.getElementById('buttons');
class View {
static ID = 0;
constructor() {
this.id = View.ID++;
this.element = document.createElement('div');
this.element.className = 'view';
this.element.style.backgroundColor = `hsl(${(this.id * 41) % 360}, 50%, 70%)`;
this.element.textContent = `${this.id}`;
this.minimumSize = 100;
this.maximumSize = Number.POSITIVE_INFINITY;
this.onDidChange = Event.None;
this.snap = true;
this.button = document.createElement('button');
this.button.onclick = () => splitview.setViewVisible(this.id, !splitview.isViewVisible(this.id));
buttons.appendChild(this.button);
this.setVisible(true);
}
layout(size, orientation) {
this.element.style.lineHeight = `${size}px`;
}
setVisible(visible) {
this.button.textContent = visible ? `hide ${this.id}` : `show ${this.id}`;
}
switch (location.search) {
case '?grid': {
require(['vs/base/browser/ui/grid/grid', 'vs/base/common/event'], ({ Grid, Sizing, Direction }, { Event }) => {
const buttons = document.getElementById('buttons');
class View {
static ID = 0;
constructor(label, minimumWidth, maximumWidth, minimumHeight, maximumHeight, snap) {
const id = View.ID++;
this.label = label;
this.minimumWidth = minimumWidth;
this.maximumWidth = maximumWidth;
this.minimumHeight = minimumHeight;
this.maximumHeight = maximumHeight;
this.snap = snap;
this.onDidChange = Event.None;
this.element = document.createElement('div');
this.element.className = 'view';
this.element.style.backgroundColor = `hsl(${(id * 41) % 360}, 50%, 70%)`;
this.element.textContent = this.label;
this.button = document.createElement('button');
this.button.onclick = () => grid.setViewVisible(this, !grid.isViewVisible(this));
buttons.appendChild(this.button);
this.setVisible(true);
}
layout(width, height, orientation) {
this.element.style.lineHeight = `${height}px`;
}
setVisible(visible) {
this.button.textContent = visible ? `hide ${this.label}` : `show ${this.label}`;
}
}
const editor = new View('editor', 200, Number.POSITIVE_INFINITY, 200, Number.POSITIVE_INFINITY);
const statusbar = new View('status', 0, Number.POSITIVE_INFINITY, 20, 20);
const activitybar = new View('activity', 50, 50, 0, Number.POSITIVE_INFINITY);
const sidebar = new View('sidebar', 200, Number.POSITIVE_INFINITY, 0, Number.POSITIVE_INFINITY, true);
const panel = new View('panel', 0, Number.POSITIVE_INFINITY, 200, Number.POSITIVE_INFINITY, true);
const grid = new Grid(editor, {});
const container = document.getElementById('container');
container.appendChild(grid.element);
grid.layout(800, 600);
grid.addView(statusbar, Sizing.Distribute, editor, Direction.Down);
grid.addView(activitybar, Sizing.Distribute, editor, Direction.Left);
grid.addView(sidebar, 250, editor, Direction.Left);
grid.addView(panel, 200, editor, Direction.Down);
});
break;
}
default: {
require(['vs/base/browser/ui/splitview/splitview', 'vs/base/common/event'], ({ SplitView, Sizing }, { Event }) => {
const buttons = document.getElementById('buttons');
class View {
static ID = 0;
constructor(minimumSize, maximumSize) {
this.id = View.ID++;
this.element = document.createElement('div');
this.element.className = 'view';
this.element.style.backgroundColor = `hsl(${(this.id * 41) % 360}, 50%, 70%)`;
this.element.textContent = `${this.id}`;
this.minimumSize = typeof minimumSize === 'number' ? minimumSize : 100;
this.maximumSize = typeof maximumSize === 'number' ? maximumSize : Number.POSITIVE_INFINITY;
this.onDidChange = Event.None;
this.snap = true;
this.button = document.createElement('button');
this.button.onclick = () => splitview.setViewVisible(this.id, !splitview.isViewVisible(this.id));
buttons.appendChild(this.button);
this.setVisible(true);
}
const container = document.getElementById('container');
const splitview = new SplitView(container, {});
splitview.layout(600);
layout(size, orientation) {
this.element.style.lineHeight = `${size}px`;
}
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
setVisible(visible) {
this.button.textContent = visible ? `hide ${this.id}` : `show ${this.id}`;
}
}
// const index = 2;
// setInterval(() => splitview.setViewVisible(index, !splitview.isViewVisible(index)), 1000);
});
const container = document.getElementById('container');
const splitview = new SplitView(container, {});
splitview.layout(600);
splitview.addView(new View(100, 100), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
splitview.addView(new View(), Sizing.Distribute);
});
}
}
</script>
</body>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册