mirror of
https://github.com/mathuo/dockview
synced 2025-09-10 03:16:34 +00:00
Merge branch 'master' of https://github.com/mathuo/dockview into master
This commit is contained in:
commit
317957c26f
@ -17,6 +17,7 @@
|
|||||||
"ES2016.Array.Include",
|
"ES2016.Array.Include",
|
||||||
"ES2017.String",
|
"ES2017.String",
|
||||||
"ES2018.Promise",
|
"ES2018.Promise",
|
||||||
|
"ES2019",
|
||||||
"DOM",
|
"DOM",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"ES2016.Array.Include",
|
"ES2016.Array.Include",
|
||||||
"ES2017.String",
|
"ES2017.String",
|
||||||
"ES2018.Promise",
|
"ES2018.Promise",
|
||||||
|
"ES2019",
|
||||||
"DOM",
|
"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();
|
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();
|
groupview.model.closeAllPanels();
|
||||||
expect(removeGroupMock).toBeCalledWith(groupview);
|
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',
|
Center = 'Center',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Quadrant = 'top' | 'bottom' | 'left' | 'right';
|
||||||
|
|
||||||
export interface DroptargetEvent {
|
export interface DroptargetEvent {
|
||||||
position: Position;
|
position: Position;
|
||||||
nativeEvent: DragEvent;
|
nativeEvent: DragEvent;
|
||||||
@ -100,60 +102,18 @@ export class Droptarget extends CompositeDisposable {
|
|||||||
const xp = (100 * x) / width;
|
const xp = (100 * x) / width;
|
||||||
const yp = (100 * y) / height;
|
const yp = (100 * y) / height;
|
||||||
|
|
||||||
let isRight = false;
|
const quadrant = this.calculateQuadrant(
|
||||||
let isLeft = false;
|
this.options.validOverlays,
|
||||||
let isTop = false;
|
xp,
|
||||||
let isBottom = false;
|
yp
|
||||||
|
);
|
||||||
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 isSmallX = width < 100;
|
const isSmallX = width < 100;
|
||||||
const isSmallY = height < 100;
|
const isSmallY = height < 100;
|
||||||
|
|
||||||
toggleClass(this.overlay, 'right', !isSmallX && isRight);
|
this.toggleClasses(quadrant, isSmallX, isSmallY);
|
||||||
toggleClass(this.overlay, 'left', !isSmallX && isLeft);
|
|
||||||
toggleClass(this.overlay, 'top', !isSmallY && isTop);
|
|
||||||
toggleClass(this.overlay, 'bottom', !isSmallY && isBottom);
|
|
||||||
|
|
||||||
toggleClass(
|
this.setState(quadrant);
|
||||||
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;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onDragLeave: (e) => {
|
onDragLeave: (e) => {
|
||||||
this.removeDropTarget();
|
this.removeDropTarget();
|
||||||
@ -181,6 +141,87 @@ export class Droptarget extends CompositeDisposable {
|
|||||||
this.removeDropTarget();
|
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() {
|
private removeDropTarget() {
|
||||||
if (this.target) {
|
if (this.target) {
|
||||||
this._state = undefined;
|
this._state = undefined;
|
||||||
|
@ -7,7 +7,7 @@ import { Position } from '../dnd/droptarget';
|
|||||||
import { tail, sequenceEquals } from '../array';
|
import { tail, sequenceEquals } from '../array';
|
||||||
import { GroupviewPanelState, IGroupPanel } from '../groupview/groupPanel';
|
import { GroupviewPanelState, IGroupPanel } from '../groupview/groupPanel';
|
||||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||||
import { CompositeDisposable, IValueDisposable } from '../lifecycle';
|
import { CompositeDisposable } from '../lifecycle';
|
||||||
import { Event, Emitter } from '../events';
|
import { Event, Emitter } from '../events';
|
||||||
import { Watermark } from './components/watermark/watermark';
|
import { Watermark } from './components/watermark/watermark';
|
||||||
import {
|
import {
|
||||||
@ -100,7 +100,6 @@ export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
|
|||||||
getGroupPanel: (id: string) => IGroupPanel | undefined;
|
getGroupPanel: (id: string) => IGroupPanel | undefined;
|
||||||
fireMouseEvent(event: LayoutMouseEvent): void;
|
fireMouseEvent(event: LayoutMouseEvent): void;
|
||||||
createWatermarkComponent(): IWatermarkRenderer;
|
createWatermarkComponent(): IWatermarkRenderer;
|
||||||
|
|
||||||
// lifecycle
|
// lifecycle
|
||||||
addEmptyGroup(options?: AddGroupOptions): void;
|
addEmptyGroup(options?: AddGroupOptions): void;
|
||||||
closeAllGroups(): void;
|
closeAllGroups(): void;
|
||||||
@ -113,13 +112,17 @@ export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
|
|||||||
focus(): void;
|
focus(): void;
|
||||||
toJSON(): SerializedDockview;
|
toJSON(): SerializedDockview;
|
||||||
fromJSON(data: SerializedDockview): void;
|
fromJSON(data: SerializedDockview): void;
|
||||||
|
//
|
||||||
|
readonly onDidRemovePanel: Event<IGroupPanel>;
|
||||||
|
readonly onDidAddPanel: Event<IGroupPanel>;
|
||||||
|
readonly onDidActivePanelChange: Event<IGroupPanel | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DockviewComponent
|
export class DockviewComponent
|
||||||
extends BaseGrid<GroupviewPanel>
|
extends BaseGrid<GroupviewPanel>
|
||||||
implements IDockviewComponent
|
implements IDockviewComponent
|
||||||
{
|
{
|
||||||
private readonly _panels = new Map<string, IValueDisposable<IGroupPanel>>();
|
// private readonly _panels = new Map<string, IValueDisposable<IGroupPanel>>();
|
||||||
|
|
||||||
// events
|
// events
|
||||||
private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>();
|
private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>();
|
||||||
@ -133,17 +136,30 @@ export class DockviewComponent
|
|||||||
private readonly _onDidDrop = new Emitter<DockviewDropEvent>();
|
private readonly _onDidDrop = new Emitter<DockviewDropEvent>();
|
||||||
readonly onDidDrop: Event<DockviewDropEvent> = this._onDidDrop.event;
|
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
|
// everything else
|
||||||
private _deserializer: IPanelDeserializer | undefined;
|
private _deserializer: IPanelDeserializer | undefined;
|
||||||
private _api: DockviewApi;
|
private _api: DockviewApi;
|
||||||
private _options: DockviewComponentOptions;
|
private _options: DockviewComponentOptions;
|
||||||
|
|
||||||
get totalPanels(): number {
|
get totalPanels(): number {
|
||||||
return this._panels.size;
|
return this.panels.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
get panels(): IGroupPanel[] {
|
get panels(): IGroupPanel[] {
|
||||||
return Array.from(this._panels.values()).map((_) => _.value);
|
return this.groups.flatMap((group) => group.model.panels);
|
||||||
}
|
}
|
||||||
|
|
||||||
get deserializer(): IPanelDeserializer | undefined {
|
get deserializer(): IPanelDeserializer | undefined {
|
||||||
@ -235,7 +251,7 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
getGroupPanel(id: string): IGroupPanel | undefined {
|
getGroupPanel(id: string): IGroupPanel | undefined {
|
||||||
return this._panels.get(id)?.value;
|
return this.panels.find((panel) => panel.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
setActivePanel(panel: IGroupPanel): void {
|
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
|
* Serialize the current state of the layout
|
||||||
*
|
*
|
||||||
@ -333,13 +320,10 @@ export class DockviewComponent
|
|||||||
toJSON(): SerializedDockview {
|
toJSON(): SerializedDockview {
|
||||||
const data = this.gridview.serialize();
|
const data = this.gridview.serialize();
|
||||||
|
|
||||||
const panels = Array.from(this._panels.values()).reduce(
|
const panels = this.panels.reduce((collection, panel) => {
|
||||||
(collection, panel) => {
|
collection[panel.id] = panel.toJSON();
|
||||||
collection[panel.value.id] = panel.value.toJSON();
|
|
||||||
return collection;
|
return collection;
|
||||||
},
|
}, {} as { [key: string]: GroupviewPanelState });
|
||||||
{} as { [key: string]: GroupviewPanelState }
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
grid: data,
|
grid: data,
|
||||||
@ -351,11 +335,9 @@ export class DockviewComponent
|
|||||||
|
|
||||||
fromJSON(data: SerializedDockview): void {
|
fromJSON(data: SerializedDockview): void {
|
||||||
this.gridview.clear();
|
this.gridview.clear();
|
||||||
this._panels.forEach((panel) => {
|
this.panels.forEach((panel) => {
|
||||||
panel.disposable.dispose();
|
panel.dispose();
|
||||||
panel.value.dispose();
|
|
||||||
});
|
});
|
||||||
this._panels.clear();
|
|
||||||
this._groups.clear();
|
this._groups.clear();
|
||||||
|
|
||||||
if (!this.deserializer) {
|
if (!this.deserializer) {
|
||||||
@ -376,9 +358,7 @@ export class DockviewComponent
|
|||||||
new DefaultDeserializer(this, {
|
new DefaultDeserializer(this, {
|
||||||
createPanel: (id) => {
|
createPanel: (id) => {
|
||||||
const panelData = panels[id];
|
const panelData = panels[id];
|
||||||
const panel = this.deserializer!.fromJSON(panelData);
|
return this.deserializer!.fromJSON(panelData);
|
||||||
this.registerPanel(panel);
|
|
||||||
return panel;
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -457,7 +437,6 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
removePanel(panel: IGroupPanel): void {
|
removePanel(panel: IGroupPanel): void {
|
||||||
this.unregisterPanel(panel);
|
|
||||||
const group = panel.group;
|
const group = panel.group;
|
||||||
|
|
||||||
if (!group) {
|
if (!group) {
|
||||||
@ -491,9 +470,9 @@ export class DockviewComponent
|
|||||||
const group = this.createGroup();
|
const group = this.createGroup();
|
||||||
|
|
||||||
if (options) {
|
if (options) {
|
||||||
const referencePanel = this._panels.get(
|
const referencePanel = this.panels.find(
|
||||||
options.referencePanel
|
(panel) => panel.id === options.referencePanel
|
||||||
)?.value;
|
);
|
||||||
|
|
||||||
if (!referencePanel) {
|
if (!referencePanel) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -551,7 +530,7 @@ export class DockviewComponent
|
|||||||
if (!target || target === Position.Center) {
|
if (!target || target === Position.Center) {
|
||||||
const groupItem: IGroupPanel | undefined =
|
const groupItem: IGroupPanel | undefined =
|
||||||
sourceGroup?.model.removePanel(itemId) ||
|
sourceGroup?.model.removePanel(itemId) ||
|
||||||
this._panels.get(itemId)?.value;
|
this.panels.find((panel) => panel.id === itemId);
|
||||||
|
|
||||||
if (!groupItem) {
|
if (!groupItem) {
|
||||||
throw new Error(`No panel with id ${itemId}`);
|
throw new Error(`No panel with id ${itemId}`);
|
||||||
@ -603,7 +582,7 @@ export class DockviewComponent
|
|||||||
} else {
|
} else {
|
||||||
const groupItem: IGroupPanel | undefined =
|
const groupItem: IGroupPanel | undefined =
|
||||||
sourceGroup?.model.removePanel(itemId) ||
|
sourceGroup?.model.removePanel(itemId) ||
|
||||||
this._panels.get(itemId)?.value;
|
this.panels.find((panel) => panel.id === itemId);
|
||||||
|
|
||||||
if (!groupItem) {
|
if (!groupItem) {
|
||||||
throw new Error(`No panel with id ${itemId}`);
|
throw new Error(`No panel with id ${itemId}`);
|
||||||
@ -632,6 +611,9 @@ export class DockviewComponent
|
|||||||
kind: GroupChangeKind.PANEL_ACTIVE,
|
kind: GroupChangeKind.PANEL_ACTIVE,
|
||||||
panel: this._activeGroup?.model.activePanel,
|
panel: this._activeGroup?.model.activePanel,
|
||||||
});
|
});
|
||||||
|
this._onDidActivePanelChange.fire(
|
||||||
|
this._activeGroup?.model.activePanel
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,24 +659,25 @@ export class DockviewComponent
|
|||||||
kind: GroupChangeKind.ADD_PANEL,
|
kind: GroupChangeKind.ADD_PANEL,
|
||||||
panel: event.panel,
|
panel: event.panel,
|
||||||
});
|
});
|
||||||
break;
|
if (event.panel) {
|
||||||
case GroupChangeKind2.GROUP_ACTIVE:
|
this._onDidAddPanel.fire(event.panel);
|
||||||
this._onGridEvent.fire({
|
}
|
||||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
|
||||||
panel: event.panel,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case GroupChangeKind2.REMOVE_PANEL:
|
case GroupChangeKind2.REMOVE_PANEL:
|
||||||
this._onGridEvent.fire({
|
this._onGridEvent.fire({
|
||||||
kind: GroupChangeKind.REMOVE_PANEL,
|
kind: GroupChangeKind.REMOVE_PANEL,
|
||||||
panel: event.panel,
|
panel: event.panel,
|
||||||
});
|
});
|
||||||
|
if (event.panel) {
|
||||||
|
this._onDidRemovePanel.fire(event.panel);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GroupChangeKind2.PANEL_ACTIVE:
|
case GroupChangeKind2.PANEL_ACTIVE:
|
||||||
this._onGridEvent.fire({
|
this._onGridEvent.fire({
|
||||||
kind: GroupChangeKind.PANEL_ACTIVE,
|
kind: GroupChangeKind.PANEL_ACTIVE,
|
||||||
panel: event.panel,
|
panel: event.panel,
|
||||||
});
|
});
|
||||||
|
this._onDidActivePanelChange.fire(event.panel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -732,7 +715,6 @@ export class DockviewComponent
|
|||||||
params: options?.params || {},
|
params: options?.params || {},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerPanel(panel);
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,4 +760,12 @@ export class DockviewComponent
|
|||||||
group.value.model.containsPanel(panel)
|
group.value.model.containsPanel(panel)
|
||||||
)?.value;
|
)?.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 { DockviewApi } from '../api/component.api';
|
||||||
import { DockviewPanelApiImpl } from '../api/groupPanelApi';
|
import { DockviewPanelApiImpl } from '../api/groupPanelApi';
|
||||||
import {
|
import {
|
||||||
@ -147,20 +146,6 @@ export class DockviewGroupPanel
|
|||||||
this._group = group;
|
this._group = group;
|
||||||
this.api.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);
|
const isPanelVisible = this._group.model.isPanelActive(this);
|
||||||
|
|
||||||
this.api._onDidActiveChange.fire({
|
this.api._onDidActiveChange.fire({
|
||||||
|
@ -74,6 +74,9 @@ export interface IBaseGrid<T extends IGridPanelView> {
|
|||||||
readonly groups: T[];
|
readonly groups: T[];
|
||||||
readonly onGridEvent: Event<GroupChangeEvent>;
|
readonly onGridEvent: Event<GroupChangeEvent>;
|
||||||
readonly onDidLayoutChange: Event<void>;
|
readonly onDidLayoutChange: Event<void>;
|
||||||
|
readonly onDidRemoveGroup: Event<T>;
|
||||||
|
readonly onDidAddGroup: Event<T>;
|
||||||
|
readonly onDidActiveGroupChange: Event<T | undefined>;
|
||||||
getPanel(id: string): T | undefined;
|
getPanel(id: string): T | undefined;
|
||||||
toJSON(): object;
|
toJSON(): object;
|
||||||
fromJSON(data: any): void;
|
fromJSON(data: any): void;
|
||||||
@ -99,6 +102,16 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
private _onDidLayoutChange = new Emitter<void>();
|
private _onDidLayoutChange = new Emitter<void>();
|
||||||
readonly onDidLayoutChange = this._onDidLayoutChange.event;
|
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() {
|
get id() {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
@ -154,8 +167,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
|
|
||||||
this.element.appendChild(this.gridview.element);
|
this.element.appendChild(this.gridview.element);
|
||||||
|
|
||||||
// TODO for some reason this is required before anything will layout correctly
|
this.layout(0, 0, true); // set some elements height/widths
|
||||||
this.layout(0, 0, true);
|
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this.gridview.onDidChange(() => {
|
this.gridview.onDidChange(() => {
|
||||||
@ -209,6 +221,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
this.gridview.addView(group, size ?? Sizing.Distribute, location);
|
this.gridview.addView(group, size ?? Sizing.Distribute, location);
|
||||||
|
|
||||||
this._onGridEvent.fire({ kind: GroupChangeKind.ADD_GROUP });
|
this._onGridEvent.fire({ kind: GroupChangeKind.ADD_GROUP });
|
||||||
|
this._onDidAddGroup.fire(group);
|
||||||
|
|
||||||
this.doSetGroupActive(group);
|
this.doSetGroupActive(group);
|
||||||
}
|
}
|
||||||
@ -231,6 +244,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._onGridEvent.fire({ kind: GroupChangeKind.REMOVE_GROUP });
|
this._onGridEvent.fire({ kind: GroupChangeKind.REMOVE_GROUP });
|
||||||
|
this._onDidRemoveGroup.fire(group);
|
||||||
|
|
||||||
if (!options?.skipActive && this._activeGroup === group) {
|
if (!options?.skipActive && this._activeGroup === group) {
|
||||||
const groups = Array.from(this._groups.values());
|
const groups = Array.from(this._groups.values());
|
||||||
@ -270,6 +284,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
this._onGridEvent.fire({
|
this._onGridEvent.fire({
|
||||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||||
});
|
});
|
||||||
|
this._onDidActiveGroupChange.fire(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeGroup(group: T) {
|
public removeGroup(group: T) {
|
||||||
@ -338,6 +353,11 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
||||||
this._onGridEvent.dispose();
|
this._onGridEvent.dispose();
|
||||||
|
this._onDidActiveGroupChange.dispose();
|
||||||
|
this._onDidAddGroup.dispose();
|
||||||
|
this._onDidRemoveGroup.dispose();
|
||||||
|
this._onDidLayoutChange.dispose();
|
||||||
|
|
||||||
this.gridview.dispose();
|
this.gridview.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,19 @@ import { Node } from './types';
|
|||||||
import { Emitter, Event } from '../events';
|
import { Emitter, Event } from '../events';
|
||||||
import { IDisposable, MutableDisposable } from '../lifecycle';
|
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>(
|
function flipNode<T extends Node>(
|
||||||
node: T,
|
node: T,
|
||||||
size: number,
|
size: number,
|
||||||
@ -289,7 +302,8 @@ export class Gridview implements IDisposable {
|
|||||||
|
|
||||||
public deserialize(json: any, deserializer: IViewDeserializer) {
|
public deserialize(json: any, deserializer: IViewDeserializer) {
|
||||||
const orientation = json.orientation;
|
const orientation = json.orientation;
|
||||||
const height = json.height;
|
const height =
|
||||||
|
orientation === Orientation.VERTICAL ? json.height : json.width;
|
||||||
this._deserialize(
|
this._deserialize(
|
||||||
json.root as ISerializedBranchNode,
|
json.root as ISerializedBranchNode,
|
||||||
orientation,
|
orientation,
|
||||||
@ -308,7 +322,8 @@ export class Gridview implements IDisposable {
|
|||||||
root,
|
root,
|
||||||
orientation,
|
orientation,
|
||||||
deserializer,
|
deserializer,
|
||||||
orthogonalSize
|
orthogonalSize,
|
||||||
|
true
|
||||||
) as BranchNode;
|
) as BranchNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +331,8 @@ export class Gridview implements IDisposable {
|
|||||||
node: ISerializedNode,
|
node: ISerializedNode,
|
||||||
orientation: Orientation,
|
orientation: Orientation,
|
||||||
deserializer: IViewDeserializer,
|
deserializer: IViewDeserializer,
|
||||||
orthogonalSize: number
|
orthogonalSize: number,
|
||||||
|
isRoot = false
|
||||||
): Node {
|
): Node {
|
||||||
let result: Node;
|
let result: Node;
|
||||||
if (node.type === 'branch') {
|
if (node.type === 'branch') {
|
||||||
@ -333,12 +349,14 @@ export class Gridview implements IDisposable {
|
|||||||
} as INodeDescriptor;
|
} as INodeDescriptor;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// HORIZONTAL => height=orthogonalsize width=size
|
||||||
|
// VERTICAL => height=size width=orthogonalsize
|
||||||
result = new BranchNode(
|
result = new BranchNode(
|
||||||
orientation,
|
orientation,
|
||||||
this.proportionalLayout,
|
this.proportionalLayout,
|
||||||
this.styles,
|
this.styles,
|
||||||
node.size,
|
isRoot ? orthogonalSize : node.size,
|
||||||
orthogonalSize,
|
isRoot ? node.size : orthogonalSize,
|
||||||
children
|
children
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -437,21 +455,6 @@ export class Gridview implements IDisposable {
|
|||||||
throw new Error('invalid location');
|
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--) {
|
for (let i = path.length - 1; i > -1; i--) {
|
||||||
const n = path[i];
|
const n = path[i];
|
||||||
const l = location[i] || 0;
|
const l = location[i] || 0;
|
||||||
|
@ -19,7 +19,6 @@ export enum GroupChangeKind2 {
|
|||||||
ADD_PANEL = 'ADD_PANEL',
|
ADD_PANEL = 'ADD_PANEL',
|
||||||
REMOVE_PANEL = 'REMOVE_PANEL',
|
REMOVE_PANEL = 'REMOVE_PANEL',
|
||||||
PANEL_ACTIVE = 'PANEL_ACTIVE',
|
PANEL_ACTIVE = 'PANEL_ACTIVE',
|
||||||
GROUP_ACTIVE = 'GROUP_ACTIVE',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DndService {
|
export interface DndService {
|
||||||
@ -365,6 +364,10 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
|||||||
) {
|
) {
|
||||||
options.index = this.panels.length;
|
options.index = this.panels.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure the group is updated before we fire any events
|
||||||
|
panel.updateParentGroup(this.parent, true);
|
||||||
|
|
||||||
if (this._activePanel === panel) {
|
if (this._activePanel === panel) {
|
||||||
this.accessor.doSetGroupActive(this.parent);
|
this.accessor.doSetGroupActive(this.parent);
|
||||||
return;
|
return;
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
PaneTransfer,
|
PaneTransfer,
|
||||||
} from '../dnd/dataTransfer';
|
} from '../dnd/dataTransfer';
|
||||||
import { Droptarget, DroptargetEvent, Position } from '../dnd/droptarget';
|
import { Droptarget, DroptargetEvent, Position } from '../dnd/droptarget';
|
||||||
import { Emitter, Event } from '../events';
|
import { Emitter } from '../events';
|
||||||
import { IDisposable } from '../lifecycle';
|
import { IDisposable } from '../lifecycle';
|
||||||
import { Orientation } from '../splitview/core/splitview';
|
import { Orientation } from '../splitview/core/splitview';
|
||||||
import {
|
import {
|
||||||
@ -14,23 +14,6 @@ import {
|
|||||||
PaneviewPanel,
|
PaneviewPanel,
|
||||||
} from './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 {
|
export interface PaneviewDropEvent2 extends DroptargetEvent {
|
||||||
panel: IPaneviewPanel;
|
panel: IPaneviewPanel;
|
||||||
getData: () => PaneTransfer | undefined;
|
getData: () => PaneTransfer | undefined;
|
||||||
@ -101,6 +84,12 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
|||||||
this.handler,
|
this.handler,
|
||||||
this.target,
|
this.target,
|
||||||
this.target.onDrop((event) => {
|
this.target.onDrop((event) => {
|
||||||
|
this.onDrop(event);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDrop(event: DroptargetEvent) {
|
||||||
const data = getPaneData();
|
const data = getPaneData();
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@ -148,7 +137,5 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
containerApi.movePanel(fromIndex, toIndex);
|
containerApi.movePanel(fromIndex, toIndex);
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user