mirror of
https://github.com/mathuo/dockview
synced 2025-08-23 02:26:36 +00:00
Merge branch 'master' of https://github.com/mathuo/dockview into master
This commit is contained in:
commit
317957c26f
@ -13,11 +13,12 @@
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"lib": [
|
||||
"ES2015",
|
||||
"ES2016.Array.Include",
|
||||
"ES2017.String",
|
||||
"ES2018.Promise",
|
||||
"DOM",
|
||||
]
|
||||
"ES2015",
|
||||
"ES2016.Array.Include",
|
||||
"ES2017.String",
|
||||
"ES2018.Promise",
|
||||
"ES2019",
|
||||
"DOM",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,12 @@
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"lib": [
|
||||
"ES2015",
|
||||
"ES2016.Array.Include",
|
||||
"ES2017.String",
|
||||
"ES2018.Promise",
|
||||
"DOM",
|
||||
]
|
||||
"ES2015",
|
||||
"ES2016.Array.Include",
|
||||
"ES2017.String",
|
||||
"ES2018.Promise",
|
||||
"ES2019",
|
||||
"DOM",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
78
packages/dockview/src/__tests__/api/groupPanelApi.spec.ts
Normal file
78
packages/dockview/src/__tests__/api/groupPanelApi.spec.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { IDockviewComponent, IGroupPanel } from '../..';
|
||||
import { DockviewPanelApiImpl, TitleEvent } from '../../api/groupPanelApi';
|
||||
import { GroupviewPanel } from '../../groupview/groupviewPanel';
|
||||
|
||||
describe('groupPanelApi', () => {
|
||||
test('title', () => {
|
||||
const groupPanel: Partial<IGroupPanel> = {
|
||||
id: 'test_id',
|
||||
title: 'test_title',
|
||||
};
|
||||
|
||||
const accessor: Partial<IDockviewComponent> = {};
|
||||
const groupViewPanel = new GroupviewPanel(
|
||||
<IDockviewComponent>accessor,
|
||||
'',
|
||||
{}
|
||||
);
|
||||
|
||||
const cut = new DockviewPanelApiImpl(
|
||||
<IGroupPanel>groupPanel,
|
||||
<GroupviewPanel>groupViewPanel
|
||||
);
|
||||
|
||||
let events: TitleEvent[] = [];
|
||||
|
||||
const disposable = cut.onDidTitleChange((event) => {
|
||||
events.push(event);
|
||||
});
|
||||
|
||||
expect(events.length).toBe(0);
|
||||
expect(cut.title).toBe('test_title');
|
||||
|
||||
cut.setTitle('test_title_2');
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0]).toEqual({ title: 'test_title_2' });
|
||||
expect(cut.title).toBe('test_title'); // title should remain unchanged
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
|
||||
test('onDidGroupChange', () => {
|
||||
const groupPanel: Partial<IGroupPanel> = {
|
||||
id: 'test_id',
|
||||
};
|
||||
|
||||
const accessor: Partial<IDockviewComponent> = {};
|
||||
const groupViewPanel = new GroupviewPanel(
|
||||
<IDockviewComponent>accessor,
|
||||
'',
|
||||
{}
|
||||
);
|
||||
|
||||
const cut = new DockviewPanelApiImpl(
|
||||
<IGroupPanel>groupPanel,
|
||||
<GroupviewPanel>groupViewPanel
|
||||
);
|
||||
|
||||
let events = 0;
|
||||
|
||||
const disposable = cut.onDidGroupChange(() => {
|
||||
events++;
|
||||
});
|
||||
|
||||
expect(events).toBe(0);
|
||||
expect(cut.group).toBe(groupViewPanel);
|
||||
|
||||
const groupViewPanel2 = new GroupviewPanel(
|
||||
<IDockviewComponent>accessor,
|
||||
'',
|
||||
{}
|
||||
);
|
||||
cut.group = groupViewPanel2;
|
||||
expect(events).toBe(1);
|
||||
expect(cut.group).toBe(groupViewPanel2);
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
});
|
@ -811,4 +811,31 @@ describe('dockviewComponent', () => {
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
|
||||
test('that removing a panel from a group reflects in the dockviewcomponent when searching for a panel', () => {
|
||||
dockview.layout(500, 500);
|
||||
|
||||
const panel1 = dockview.addPanel({
|
||||
id: 'panel1',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
const panel2 = dockview.addPanel({
|
||||
id: 'panel2',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(dockview.getGroupPanel('panel1')).toEqual(panel1);
|
||||
expect(dockview.getGroupPanel('panel2')).toEqual(panel2);
|
||||
|
||||
panel1.group.model.removePanel(panel1);
|
||||
|
||||
expect(dockview.getGroupPanel('panel1')).toBeUndefined();
|
||||
expect(dockview.getGroupPanel('panel2')).toEqual(panel2);
|
||||
|
||||
dockview.removePanel(panel2);
|
||||
|
||||
expect(dockview.getGroupPanel('panel1')).toBeUndefined();
|
||||
expect(dockview.getGroupPanel('panel2')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -444,4 +444,19 @@ describe('groupview', () => {
|
||||
groupview.model.closeAllPanels();
|
||||
expect(removeGroupMock).toBeCalledWith(groupview);
|
||||
});
|
||||
|
||||
test('that group is set on panel during onDidAddPanel event', () => {
|
||||
const cut = new DockviewComponent(document.createElement('div'), {
|
||||
components: {
|
||||
component: TestContentPart,
|
||||
},
|
||||
});
|
||||
|
||||
const disposable = cut.onDidAddPanel((panel) => {
|
||||
expect(panel.group).toBeTruthy();
|
||||
});
|
||||
|
||||
const panel = cut.addPanel({ id: 'id', component: 'component' });
|
||||
disposable.dispose();
|
||||
});
|
||||
});
|
||||
|
@ -11,6 +11,8 @@ export enum Position {
|
||||
Center = 'Center',
|
||||
}
|
||||
|
||||
type Quadrant = 'top' | 'bottom' | 'left' | 'right';
|
||||
|
||||
export interface DroptargetEvent {
|
||||
position: Position;
|
||||
nativeEvent: DragEvent;
|
||||
@ -100,60 +102,18 @@ export class Droptarget extends CompositeDisposable {
|
||||
const xp = (100 * x) / width;
|
||||
const yp = (100 * y) / height;
|
||||
|
||||
let isRight = false;
|
||||
let isLeft = false;
|
||||
let isTop = false;
|
||||
let isBottom = false;
|
||||
|
||||
switch (this.options.validOverlays) {
|
||||
case 'all':
|
||||
isRight = xp > 80;
|
||||
isLeft = xp < 20;
|
||||
isTop = !isRight && !isLeft && yp < 20;
|
||||
isBottom = !isRight && !isLeft && yp > 80;
|
||||
break;
|
||||
case 'vertical':
|
||||
isTop = yp < 50;
|
||||
isBottom = yp >= 50;
|
||||
break;
|
||||
case 'horizontal':
|
||||
isLeft = xp < 50;
|
||||
isRight = xp >= 50;
|
||||
break;
|
||||
}
|
||||
const quadrant = this.calculateQuadrant(
|
||||
this.options.validOverlays,
|
||||
xp,
|
||||
yp
|
||||
);
|
||||
|
||||
const isSmallX = width < 100;
|
||||
const isSmallY = height < 100;
|
||||
|
||||
toggleClass(this.overlay, 'right', !isSmallX && isRight);
|
||||
toggleClass(this.overlay, 'left', !isSmallX && isLeft);
|
||||
toggleClass(this.overlay, 'top', !isSmallY && isTop);
|
||||
toggleClass(this.overlay, 'bottom', !isSmallY && isBottom);
|
||||
this.toggleClasses(quadrant, isSmallX, isSmallY);
|
||||
|
||||
toggleClass(
|
||||
this.overlay,
|
||||
'small-right',
|
||||
isSmallX && isRight
|
||||
);
|
||||
toggleClass(this.overlay, 'small-left', isSmallX && isLeft);
|
||||
toggleClass(this.overlay, 'small-top', isSmallY && isTop);
|
||||
toggleClass(
|
||||
this.overlay,
|
||||
'small-bottom',
|
||||
isSmallY && isBottom
|
||||
);
|
||||
|
||||
if (isRight) {
|
||||
this._state = Position.Right;
|
||||
} else if (isLeft) {
|
||||
this._state = Position.Left;
|
||||
} else if (isTop) {
|
||||
this._state = Position.Top;
|
||||
} else if (isBottom) {
|
||||
this._state = Position.Bottom;
|
||||
} else {
|
||||
this._state = Position.Center;
|
||||
}
|
||||
this.setState(quadrant);
|
||||
},
|
||||
onDragLeave: (e) => {
|
||||
this.removeDropTarget();
|
||||
@ -181,6 +141,87 @@ export class Droptarget extends CompositeDisposable {
|
||||
this.removeDropTarget();
|
||||
}
|
||||
|
||||
private toggleClasses(
|
||||
quadrant: Quadrant | null,
|
||||
isSmallX: boolean,
|
||||
isSmallY: boolean
|
||||
) {
|
||||
if (!this.overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isLeft = quadrant === 'left';
|
||||
const isRight = quadrant === 'right';
|
||||
const isTop = quadrant === 'top';
|
||||
const isBottom = quadrant === 'bottom';
|
||||
|
||||
toggleClass(this.overlay, 'right', !isSmallX && isRight);
|
||||
toggleClass(this.overlay, 'left', !isSmallX && isLeft);
|
||||
toggleClass(this.overlay, 'top', !isSmallY && isTop);
|
||||
toggleClass(this.overlay, 'bottom', !isSmallY && isBottom);
|
||||
|
||||
toggleClass(this.overlay, 'small-right', isSmallX && isRight);
|
||||
toggleClass(this.overlay, 'small-left', isSmallX && isLeft);
|
||||
toggleClass(this.overlay, 'small-top', isSmallY && isTop);
|
||||
toggleClass(this.overlay, 'small-bottom', isSmallY && isBottom);
|
||||
}
|
||||
|
||||
private setState(quadrant: Quadrant | null) {
|
||||
switch (quadrant) {
|
||||
case 'top':
|
||||
this._state = Position.Top;
|
||||
break;
|
||||
case 'left':
|
||||
this._state = Position.Left;
|
||||
break;
|
||||
case 'bottom':
|
||||
this._state = Position.Bottom;
|
||||
break;
|
||||
case 'right':
|
||||
this._state = Position.Right;
|
||||
break;
|
||||
default:
|
||||
this._state = Position.Center;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private calculateQuadrant(
|
||||
overlayType: DropTargetDirections,
|
||||
xp: number,
|
||||
yp: number
|
||||
): Quadrant | null {
|
||||
switch (overlayType) {
|
||||
case 'all':
|
||||
if (xp < 20) {
|
||||
return 'left';
|
||||
}
|
||||
if (xp > 80) {
|
||||
return 'right';
|
||||
}
|
||||
if (yp < 20) {
|
||||
return 'top';
|
||||
}
|
||||
if (yp > 80) {
|
||||
return 'bottom';
|
||||
}
|
||||
break;
|
||||
case 'vertical':
|
||||
if (yp < 50) {
|
||||
return 'top';
|
||||
}
|
||||
return 'bottom';
|
||||
|
||||
case 'horizontal':
|
||||
if (xp < 50) {
|
||||
return 'left';
|
||||
}
|
||||
return 'right';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private removeDropTarget() {
|
||||
if (this.target) {
|
||||
this._state = undefined;
|
||||
|
@ -7,7 +7,7 @@ import { Position } from '../dnd/droptarget';
|
||||
import { tail, sequenceEquals } from '../array';
|
||||
import { GroupviewPanelState, IGroupPanel } from '../groupview/groupPanel';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { CompositeDisposable, IValueDisposable } from '../lifecycle';
|
||||
import { CompositeDisposable } from '../lifecycle';
|
||||
import { Event, Emitter } from '../events';
|
||||
import { Watermark } from './components/watermark/watermark';
|
||||
import {
|
||||
@ -100,7 +100,6 @@ export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
|
||||
getGroupPanel: (id: string) => IGroupPanel | undefined;
|
||||
fireMouseEvent(event: LayoutMouseEvent): void;
|
||||
createWatermarkComponent(): IWatermarkRenderer;
|
||||
|
||||
// lifecycle
|
||||
addEmptyGroup(options?: AddGroupOptions): void;
|
||||
closeAllGroups(): void;
|
||||
@ -113,13 +112,17 @@ export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
|
||||
focus(): void;
|
||||
toJSON(): SerializedDockview;
|
||||
fromJSON(data: SerializedDockview): void;
|
||||
//
|
||||
readonly onDidRemovePanel: Event<IGroupPanel>;
|
||||
readonly onDidAddPanel: Event<IGroupPanel>;
|
||||
readonly onDidActivePanelChange: Event<IGroupPanel | undefined>;
|
||||
}
|
||||
|
||||
export class DockviewComponent
|
||||
extends BaseGrid<GroupviewPanel>
|
||||
implements IDockviewComponent
|
||||
{
|
||||
private readonly _panels = new Map<string, IValueDisposable<IGroupPanel>>();
|
||||
// private readonly _panels = new Map<string, IValueDisposable<IGroupPanel>>();
|
||||
|
||||
// events
|
||||
private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>();
|
||||
@ -133,17 +136,30 @@ export class DockviewComponent
|
||||
private readonly _onDidDrop = new Emitter<DockviewDropEvent>();
|
||||
readonly onDidDrop: Event<DockviewDropEvent> = this._onDidDrop.event;
|
||||
|
||||
private readonly _onDidRemovePanel = new Emitter<IGroupPanel>();
|
||||
readonly onDidRemovePanel: Event<IGroupPanel> =
|
||||
this._onDidRemovePanel.event;
|
||||
|
||||
private readonly _onDidAddPanel = new Emitter<IGroupPanel>();
|
||||
readonly onDidAddPanel: Event<IGroupPanel> = this._onDidAddPanel.event;
|
||||
|
||||
private readonly _onDidActivePanelChange = new Emitter<
|
||||
IGroupPanel | undefined
|
||||
>();
|
||||
readonly onDidActivePanelChange: Event<IGroupPanel | undefined> =
|
||||
this._onDidActivePanelChange.event;
|
||||
|
||||
// everything else
|
||||
private _deserializer: IPanelDeserializer | undefined;
|
||||
private _api: DockviewApi;
|
||||
private _options: DockviewComponentOptions;
|
||||
|
||||
get totalPanels(): number {
|
||||
return this._panels.size;
|
||||
return this.panels.length;
|
||||
}
|
||||
|
||||
get panels(): IGroupPanel[] {
|
||||
return Array.from(this._panels.values()).map((_) => _.value);
|
||||
return this.groups.flatMap((group) => group.model.panels);
|
||||
}
|
||||
|
||||
get deserializer(): IPanelDeserializer | undefined {
|
||||
@ -235,7 +251,7 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
getGroupPanel(id: string): IGroupPanel | undefined {
|
||||
return this._panels.get(id)?.value;
|
||||
return this.panels.find((panel) => panel.id === id);
|
||||
}
|
||||
|
||||
setActivePanel(panel: IGroupPanel): void {
|
||||
@ -296,35 +312,6 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
private registerPanel(panel: IGroupPanel): void {
|
||||
if (this._panels.has(panel.id)) {
|
||||
throw new Error(`panel ${panel.id} already exists`);
|
||||
}
|
||||
|
||||
this._panels.set(panel.id, {
|
||||
value: panel,
|
||||
disposable: {
|
||||
dispose: () => {
|
||||
/** noop */
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private unregisterPanel(panel: IGroupPanel): void {
|
||||
if (!this._panels.has(panel.id)) {
|
||||
throw new Error(`panel ${panel.id} doesn't exist`);
|
||||
}
|
||||
const item = this._panels.get(panel.id);
|
||||
|
||||
if (item) {
|
||||
item.disposable.dispose();
|
||||
item.value.dispose();
|
||||
}
|
||||
|
||||
this._panels.delete(panel.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current state of the layout
|
||||
*
|
||||
@ -333,13 +320,10 @@ export class DockviewComponent
|
||||
toJSON(): SerializedDockview {
|
||||
const data = this.gridview.serialize();
|
||||
|
||||
const panels = Array.from(this._panels.values()).reduce(
|
||||
(collection, panel) => {
|
||||
collection[panel.value.id] = panel.value.toJSON();
|
||||
return collection;
|
||||
},
|
||||
{} as { [key: string]: GroupviewPanelState }
|
||||
);
|
||||
const panels = this.panels.reduce((collection, panel) => {
|
||||
collection[panel.id] = panel.toJSON();
|
||||
return collection;
|
||||
}, {} as { [key: string]: GroupviewPanelState });
|
||||
|
||||
return {
|
||||
grid: data,
|
||||
@ -351,11 +335,9 @@ export class DockviewComponent
|
||||
|
||||
fromJSON(data: SerializedDockview): void {
|
||||
this.gridview.clear();
|
||||
this._panels.forEach((panel) => {
|
||||
panel.disposable.dispose();
|
||||
panel.value.dispose();
|
||||
this.panels.forEach((panel) => {
|
||||
panel.dispose();
|
||||
});
|
||||
this._panels.clear();
|
||||
this._groups.clear();
|
||||
|
||||
if (!this.deserializer) {
|
||||
@ -376,9 +358,7 @@ export class DockviewComponent
|
||||
new DefaultDeserializer(this, {
|
||||
createPanel: (id) => {
|
||||
const panelData = panels[id];
|
||||
const panel = this.deserializer!.fromJSON(panelData);
|
||||
this.registerPanel(panel);
|
||||
return panel;
|
||||
return this.deserializer!.fromJSON(panelData);
|
||||
},
|
||||
})
|
||||
);
|
||||
@ -457,7 +437,6 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
removePanel(panel: IGroupPanel): void {
|
||||
this.unregisterPanel(panel);
|
||||
const group = panel.group;
|
||||
|
||||
if (!group) {
|
||||
@ -491,9 +470,9 @@ export class DockviewComponent
|
||||
const group = this.createGroup();
|
||||
|
||||
if (options) {
|
||||
const referencePanel = this._panels.get(
|
||||
options.referencePanel
|
||||
)?.value;
|
||||
const referencePanel = this.panels.find(
|
||||
(panel) => panel.id === options.referencePanel
|
||||
);
|
||||
|
||||
if (!referencePanel) {
|
||||
throw new Error(
|
||||
@ -551,7 +530,7 @@ export class DockviewComponent
|
||||
if (!target || target === Position.Center) {
|
||||
const groupItem: IGroupPanel | undefined =
|
||||
sourceGroup?.model.removePanel(itemId) ||
|
||||
this._panels.get(itemId)?.value;
|
||||
this.panels.find((panel) => panel.id === itemId);
|
||||
|
||||
if (!groupItem) {
|
||||
throw new Error(`No panel with id ${itemId}`);
|
||||
@ -603,7 +582,7 @@ export class DockviewComponent
|
||||
} else {
|
||||
const groupItem: IGroupPanel | undefined =
|
||||
sourceGroup?.model.removePanel(itemId) ||
|
||||
this._panels.get(itemId)?.value;
|
||||
this.panels.find((panel) => panel.id === itemId);
|
||||
|
||||
if (!groupItem) {
|
||||
throw new Error(`No panel with id ${itemId}`);
|
||||
@ -632,6 +611,9 @@ export class DockviewComponent
|
||||
kind: GroupChangeKind.PANEL_ACTIVE,
|
||||
panel: this._activeGroup?.model.activePanel,
|
||||
});
|
||||
this._onDidActivePanelChange.fire(
|
||||
this._activeGroup?.model.activePanel
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -677,24 +659,25 @@ export class DockviewComponent
|
||||
kind: GroupChangeKind.ADD_PANEL,
|
||||
panel: event.panel,
|
||||
});
|
||||
break;
|
||||
case GroupChangeKind2.GROUP_ACTIVE:
|
||||
this._onGridEvent.fire({
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
panel: event.panel,
|
||||
});
|
||||
if (event.panel) {
|
||||
this._onDidAddPanel.fire(event.panel);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind2.REMOVE_PANEL:
|
||||
this._onGridEvent.fire({
|
||||
kind: GroupChangeKind.REMOVE_PANEL,
|
||||
panel: event.panel,
|
||||
});
|
||||
if (event.panel) {
|
||||
this._onDidRemovePanel.fire(event.panel);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind2.PANEL_ACTIVE:
|
||||
this._onGridEvent.fire({
|
||||
kind: GroupChangeKind.PANEL_ACTIVE,
|
||||
panel: event.panel,
|
||||
});
|
||||
this._onDidActivePanelChange.fire(event.panel);
|
||||
break;
|
||||
}
|
||||
})
|
||||
@ -732,7 +715,6 @@ export class DockviewComponent
|
||||
params: options?.params || {},
|
||||
});
|
||||
|
||||
this.registerPanel(panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@ -778,4 +760,12 @@ export class DockviewComponent
|
||||
group.value.model.containsPanel(panel)
|
||||
)?.value;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this._onDidActivePanelChange.dispose();
|
||||
this._onDidAddPanel.dispose();
|
||||
this._onDidRemovePanel.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { GroupChangeKind2 } from '../groupview/groupview';
|
||||
import { DockviewApi } from '../api/component.api';
|
||||
import { DockviewPanelApiImpl } from '../api/groupPanelApi';
|
||||
import {
|
||||
@ -147,20 +146,6 @@ export class DockviewGroupPanel
|
||||
this._group = group;
|
||||
this.api.group = group;
|
||||
|
||||
this.mutableDisposable.value = this._group.model.onDidGroupChange(
|
||||
(ev) => {
|
||||
if (ev.kind === GroupChangeKind2.GROUP_ACTIVE) {
|
||||
const isVisible = !!this._group?.model.isPanelActive(this);
|
||||
this.api._onDidActiveChange.fire({
|
||||
isActive: isGroupActive && isVisible,
|
||||
});
|
||||
this.api._onDidVisibilityChange.fire({
|
||||
isVisible,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const isPanelVisible = this._group.model.isPanelActive(this);
|
||||
|
||||
this.api._onDidActiveChange.fire({
|
||||
|
@ -74,6 +74,9 @@ export interface IBaseGrid<T extends IGridPanelView> {
|
||||
readonly groups: T[];
|
||||
readonly onGridEvent: Event<GroupChangeEvent>;
|
||||
readonly onDidLayoutChange: Event<void>;
|
||||
readonly onDidRemoveGroup: Event<T>;
|
||||
readonly onDidAddGroup: Event<T>;
|
||||
readonly onDidActiveGroupChange: Event<T | undefined>;
|
||||
getPanel(id: string): T | undefined;
|
||||
toJSON(): object;
|
||||
fromJSON(data: any): void;
|
||||
@ -99,6 +102,16 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
private _onDidLayoutChange = new Emitter<void>();
|
||||
readonly onDidLayoutChange = this._onDidLayoutChange.event;
|
||||
|
||||
private readonly _onDidRemoveGroup = new Emitter<T>();
|
||||
readonly onDidRemoveGroup: Event<T> = this._onDidRemoveGroup.event;
|
||||
|
||||
private readonly _onDidAddGroup = new Emitter<T>();
|
||||
readonly onDidAddGroup: Event<T> = this._onDidAddGroup.event;
|
||||
|
||||
private readonly _onDidActiveGroupChange = new Emitter<T | undefined>();
|
||||
readonly onDidActiveGroupChange: Event<T | undefined> =
|
||||
this._onDidActiveGroupChange.event;
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
@ -154,8 +167,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
|
||||
this.element.appendChild(this.gridview.element);
|
||||
|
||||
// TODO for some reason this is required before anything will layout correctly
|
||||
this.layout(0, 0, true);
|
||||
this.layout(0, 0, true); // set some elements height/widths
|
||||
|
||||
this.addDisposables(
|
||||
this.gridview.onDidChange(() => {
|
||||
@ -209,6 +221,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
this.gridview.addView(group, size ?? Sizing.Distribute, location);
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.ADD_GROUP });
|
||||
this._onDidAddGroup.fire(group);
|
||||
|
||||
this.doSetGroupActive(group);
|
||||
}
|
||||
@ -231,6 +244,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
}
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.REMOVE_GROUP });
|
||||
this._onDidRemoveGroup.fire(group);
|
||||
|
||||
if (!options?.skipActive && this._activeGroup === group) {
|
||||
const groups = Array.from(this._groups.values());
|
||||
@ -270,6 +284,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
this._onGridEvent.fire({
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
});
|
||||
this._onDidActiveGroupChange.fire(group);
|
||||
}
|
||||
|
||||
public removeGroup(group: T) {
|
||||
@ -338,6 +353,11 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
super.dispose();
|
||||
|
||||
this._onGridEvent.dispose();
|
||||
this._onDidActiveGroupChange.dispose();
|
||||
this._onDidAddGroup.dispose();
|
||||
this._onDidRemoveGroup.dispose();
|
||||
this._onDidLayoutChange.dispose();
|
||||
|
||||
this.gridview.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,19 @@ import { Node } from './types';
|
||||
import { Emitter, Event } from '../events';
|
||||
import { IDisposable, MutableDisposable } from '../lifecycle';
|
||||
|
||||
function findLeaf(candiateNode: Node, last: boolean): LeafNode {
|
||||
if (candiateNode instanceof LeafNode) {
|
||||
return candiateNode;
|
||||
}
|
||||
if (candiateNode instanceof BranchNode) {
|
||||
return findLeaf(
|
||||
candiateNode.children[last ? candiateNode.children.length - 1 : 0],
|
||||
last
|
||||
);
|
||||
}
|
||||
throw new Error('invalid node');
|
||||
}
|
||||
|
||||
function flipNode<T extends Node>(
|
||||
node: T,
|
||||
size: number,
|
||||
@ -289,7 +302,8 @@ export class Gridview implements IDisposable {
|
||||
|
||||
public deserialize(json: any, deserializer: IViewDeserializer) {
|
||||
const orientation = json.orientation;
|
||||
const height = json.height;
|
||||
const height =
|
||||
orientation === Orientation.VERTICAL ? json.height : json.width;
|
||||
this._deserialize(
|
||||
json.root as ISerializedBranchNode,
|
||||
orientation,
|
||||
@ -308,7 +322,8 @@ export class Gridview implements IDisposable {
|
||||
root,
|
||||
orientation,
|
||||
deserializer,
|
||||
orthogonalSize
|
||||
orthogonalSize,
|
||||
true
|
||||
) as BranchNode;
|
||||
}
|
||||
|
||||
@ -316,7 +331,8 @@ export class Gridview implements IDisposable {
|
||||
node: ISerializedNode,
|
||||
orientation: Orientation,
|
||||
deserializer: IViewDeserializer,
|
||||
orthogonalSize: number
|
||||
orthogonalSize: number,
|
||||
isRoot = false
|
||||
): Node {
|
||||
let result: Node;
|
||||
if (node.type === 'branch') {
|
||||
@ -333,12 +349,14 @@ export class Gridview implements IDisposable {
|
||||
} as INodeDescriptor;
|
||||
});
|
||||
|
||||
// HORIZONTAL => height=orthogonalsize width=size
|
||||
// VERTICAL => height=size width=orthogonalsize
|
||||
result = new BranchNode(
|
||||
orientation,
|
||||
this.proportionalLayout,
|
||||
this.styles,
|
||||
node.size,
|
||||
orthogonalSize,
|
||||
isRoot ? orthogonalSize : node.size,
|
||||
isRoot ? node.size : orthogonalSize,
|
||||
children
|
||||
);
|
||||
} else {
|
||||
@ -437,21 +455,6 @@ export class Gridview implements IDisposable {
|
||||
throw new Error('invalid location');
|
||||
}
|
||||
|
||||
const findLeaf = (candiateNode: Node, last: boolean): LeafNode => {
|
||||
if (candiateNode instanceof LeafNode) {
|
||||
return candiateNode;
|
||||
}
|
||||
if (candiateNode instanceof BranchNode) {
|
||||
return findLeaf(
|
||||
candiateNode.children[
|
||||
last ? candiateNode.children.length - 1 : 0
|
||||
],
|
||||
last
|
||||
);
|
||||
}
|
||||
throw new Error('invalid node');
|
||||
};
|
||||
|
||||
for (let i = path.length - 1; i > -1; i--) {
|
||||
const n = path[i];
|
||||
const l = location[i] || 0;
|
||||
|
@ -19,7 +19,6 @@ export enum GroupChangeKind2 {
|
||||
ADD_PANEL = 'ADD_PANEL',
|
||||
REMOVE_PANEL = 'REMOVE_PANEL',
|
||||
PANEL_ACTIVE = 'PANEL_ACTIVE',
|
||||
GROUP_ACTIVE = 'GROUP_ACTIVE',
|
||||
}
|
||||
|
||||
export interface DndService {
|
||||
@ -365,6 +364,10 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
) {
|
||||
options.index = this.panels.length;
|
||||
}
|
||||
|
||||
// ensure the group is updated before we fire any events
|
||||
panel.updateParentGroup(this.parent, true);
|
||||
|
||||
if (this._activePanel === panel) {
|
||||
this.accessor.doSetGroupActive(this.parent);
|
||||
return;
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
PaneTransfer,
|
||||
} from '../dnd/dataTransfer';
|
||||
import { Droptarget, DroptargetEvent, Position } from '../dnd/droptarget';
|
||||
import { Emitter, Event } from '../events';
|
||||
import { Emitter } from '../events';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { Orientation } from '../splitview/core/splitview';
|
||||
import {
|
||||
@ -14,23 +14,6 @@ import {
|
||||
PaneviewPanel,
|
||||
} from './paneviewPanel';
|
||||
|
||||
interface ViewContainer {
|
||||
readonly title: string;
|
||||
readonly icon: string;
|
||||
}
|
||||
|
||||
interface ViewContainerModel {
|
||||
readonly title: string;
|
||||
readonly icon: string;
|
||||
readonly onDidAdd: Event<void>;
|
||||
readonly onDidRemove: Event<void>;
|
||||
}
|
||||
|
||||
interface IViewContainerService {
|
||||
getViewContainerById(id: string): ViewContainer;
|
||||
getViewContainerModel(container: ViewContainer): ViewContainerModel;
|
||||
}
|
||||
|
||||
export interface PaneviewDropEvent2 extends DroptargetEvent {
|
||||
panel: IPaneviewPanel;
|
||||
getData: () => PaneTransfer | undefined;
|
||||
@ -101,54 +84,58 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
||||
this.handler,
|
||||
this.target,
|
||||
this.target.onDrop((event) => {
|
||||
const data = getPaneData();
|
||||
|
||||
if (!data) {
|
||||
this._onDidDrop.fire({
|
||||
...event,
|
||||
panel: this,
|
||||
getData: () => getPaneData(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const containerApi = (this._params! as PanePanelInitParameter)
|
||||
.containerApi;
|
||||
const panelId = data.paneId;
|
||||
|
||||
const existingPanel = containerApi.getPanel(panelId);
|
||||
if (!existingPanel) {
|
||||
this._onDidDrop.fire({
|
||||
...event,
|
||||
panel: this,
|
||||
getData: () => getPaneData(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const allPanels = containerApi.getPanels();
|
||||
|
||||
const fromIndex = allPanels.indexOf(existingPanel);
|
||||
let toIndex = containerApi.getPanels().indexOf(this);
|
||||
|
||||
if (
|
||||
event.position === Position.Left ||
|
||||
event.position === Position.Top
|
||||
) {
|
||||
toIndex = Math.max(0, toIndex - 1);
|
||||
}
|
||||
if (
|
||||
event.position === Position.Right ||
|
||||
event.position === Position.Bottom
|
||||
) {
|
||||
if (fromIndex > toIndex) {
|
||||
toIndex++;
|
||||
}
|
||||
toIndex = Math.min(allPanels.length - 1, toIndex);
|
||||
}
|
||||
|
||||
containerApi.movePanel(fromIndex, toIndex);
|
||||
this.onDrop(event);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private onDrop(event: DroptargetEvent) {
|
||||
const data = getPaneData();
|
||||
|
||||
if (!data) {
|
||||
this._onDidDrop.fire({
|
||||
...event,
|
||||
panel: this,
|
||||
getData: () => getPaneData(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const containerApi = (this._params! as PanePanelInitParameter)
|
||||
.containerApi;
|
||||
const panelId = data.paneId;
|
||||
|
||||
const existingPanel = containerApi.getPanel(panelId);
|
||||
if (!existingPanel) {
|
||||
this._onDidDrop.fire({
|
||||
...event,
|
||||
panel: this,
|
||||
getData: () => getPaneData(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const allPanels = containerApi.getPanels();
|
||||
|
||||
const fromIndex = allPanels.indexOf(existingPanel);
|
||||
let toIndex = containerApi.getPanels().indexOf(this);
|
||||
|
||||
if (
|
||||
event.position === Position.Left ||
|
||||
event.position === Position.Top
|
||||
) {
|
||||
toIndex = Math.max(0, toIndex - 1);
|
||||
}
|
||||
if (
|
||||
event.position === Position.Right ||
|
||||
event.position === Position.Bottom
|
||||
) {
|
||||
if (fromIndex > toIndex) {
|
||||
toIndex++;
|
||||
}
|
||||
toIndex = Math.min(allPanels.length - 1, toIndex);
|
||||
}
|
||||
|
||||
containerApi.movePanel(fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user