mirror of
https://github.com/mathuo/dockview
synced 2025-02-08 17:35:44 +00:00
feat: serialization of maximized views
This commit is contained in:
parent
24cc974a68
commit
2f4150013b
@ -679,180 +679,231 @@ describe('dockviewComponent', () => {
|
|||||||
expect(viewQuery.length).toBe(1);
|
expect(viewQuery.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('serialization', () => {
|
describe('serialization', () => {
|
||||||
dockview.layout(1000, 1000);
|
test('basic', () => {
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
root: {
|
root: {
|
||||||
type: 'branch',
|
type: 'branch',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
type: 'leaf',
|
type: 'leaf',
|
||||||
data: {
|
data: {
|
||||||
views: ['panel1'],
|
views: ['panel1'],
|
||||||
id: 'group-1',
|
id: 'group-1',
|
||||||
activeView: 'panel1',
|
activeView: 'panel1',
|
||||||
|
},
|
||||||
|
size: 500,
|
||||||
},
|
},
|
||||||
size: 500,
|
{
|
||||||
},
|
type: 'branch',
|
||||||
{
|
data: [
|
||||||
type: 'branch',
|
{
|
||||||
data: [
|
type: 'leaf',
|
||||||
{
|
data: {
|
||||||
type: 'leaf',
|
views: ['panel2', 'panel3'],
|
||||||
data: {
|
id: 'group-2',
|
||||||
views: ['panel2', 'panel3'],
|
},
|
||||||
id: 'group-2',
|
size: 500,
|
||||||
},
|
},
|
||||||
size: 500,
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel4'],
|
||||||
|
id: 'group-3',
|
||||||
|
},
|
||||||
|
size: 500,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: { views: ['panel5'], id: 'group-4' },
|
||||||
|
size: 250,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
},
|
||||||
|
height: 1000,
|
||||||
|
width: 1000,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
},
|
||||||
|
panels: {
|
||||||
|
panel1: {
|
||||||
|
id: 'panel1',
|
||||||
|
contentComponent: 'default',
|
||||||
|
tabComponent: 'tab-default',
|
||||||
|
title: 'panel1',
|
||||||
|
},
|
||||||
|
panel2: {
|
||||||
|
id: 'panel2',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel2',
|
||||||
|
},
|
||||||
|
panel3: {
|
||||||
|
id: 'panel3',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel3',
|
||||||
|
renderer: 'onlyWhenVisible',
|
||||||
|
},
|
||||||
|
panel4: {
|
||||||
|
id: 'panel4',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel4',
|
||||||
|
renderer: 'always',
|
||||||
|
},
|
||||||
|
panel5: {
|
||||||
|
id: 'panel5',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel5',
|
||||||
|
minimumHeight: 100,
|
||||||
|
maximumHeight: 1000,
|
||||||
|
minimumWidth: 200,
|
||||||
|
maximumWidth: 2000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||||
|
activeGroup: 'group-1',
|
||||||
|
grid: {
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel1'],
|
||||||
|
id: 'group-1',
|
||||||
|
activeView: 'panel1',
|
||||||
},
|
},
|
||||||
{
|
size: 500,
|
||||||
type: 'leaf',
|
},
|
||||||
data: { views: ['panel4'], id: 'group-3' },
|
{
|
||||||
size: 500,
|
type: 'branch',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel2', 'panel3'],
|
||||||
|
id: 'group-2',
|
||||||
|
activeView: 'panel3',
|
||||||
|
},
|
||||||
|
size: 500,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel4'],
|
||||||
|
id: 'group-3',
|
||||||
|
activeView: 'panel4',
|
||||||
|
},
|
||||||
|
size: 500,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel5'],
|
||||||
|
id: 'group-4',
|
||||||
|
activeView: 'panel5',
|
||||||
},
|
},
|
||||||
],
|
size: 250,
|
||||||
size: 250,
|
},
|
||||||
},
|
],
|
||||||
{
|
size: 1000,
|
||||||
type: 'leaf',
|
},
|
||||||
data: { views: ['panel5'], id: 'group-4' },
|
height: 1000,
|
||||||
size: 250,
|
width: 1000,
|
||||||
},
|
orientation: Orientation.VERTICAL,
|
||||||
],
|
|
||||||
size: 1000,
|
|
||||||
},
|
},
|
||||||
height: 1000,
|
panels: {
|
||||||
width: 1000,
|
panel1: {
|
||||||
orientation: Orientation.VERTICAL,
|
id: 'panel1',
|
||||||
},
|
contentComponent: 'default',
|
||||||
panels: {
|
tabComponent: 'tab-default',
|
||||||
panel1: {
|
title: 'panel1',
|
||||||
id: 'panel1',
|
},
|
||||||
contentComponent: 'default',
|
panel2: {
|
||||||
tabComponent: 'tab-default',
|
id: 'panel2',
|
||||||
title: 'panel1',
|
contentComponent: 'default',
|
||||||
|
title: 'panel2',
|
||||||
|
},
|
||||||
|
panel3: {
|
||||||
|
id: 'panel3',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel3',
|
||||||
|
renderer: 'onlyWhenVisible',
|
||||||
|
},
|
||||||
|
panel4: {
|
||||||
|
id: 'panel4',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel4',
|
||||||
|
renderer: 'always',
|
||||||
|
},
|
||||||
|
panel5: {
|
||||||
|
id: 'panel5',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel5',
|
||||||
|
minimumHeight: 100,
|
||||||
|
maximumHeight: 1000,
|
||||||
|
minimumWidth: 200,
|
||||||
|
maximumWidth: 2000,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
panel2: {
|
});
|
||||||
id: 'panel2',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel2',
|
|
||||||
},
|
|
||||||
panel3: {
|
|
||||||
id: 'panel3',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel3',
|
|
||||||
renderer: 'onlyWhenVisible',
|
|
||||||
},
|
|
||||||
panel4: {
|
|
||||||
id: 'panel4',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel4',
|
|
||||||
renderer: 'always',
|
|
||||||
},
|
|
||||||
panel5: {
|
|
||||||
id: 'panel5',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel5',
|
|
||||||
minimumHeight: 100,
|
|
||||||
maximumHeight: 1000,
|
|
||||||
minimumWidth: 200,
|
|
||||||
maximumWidth: 2000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
test('serialized layout with maximized node', () => {
|
||||||
activeGroup: 'group-1',
|
const api = new DockviewApi(dockview);
|
||||||
grid: {
|
|
||||||
root: {
|
api.layout(500, 1000);
|
||||||
type: 'branch',
|
|
||||||
data: [
|
api.addPanel({
|
||||||
{
|
id: 'panel1',
|
||||||
type: 'leaf',
|
component: 'default',
|
||||||
data: {
|
});
|
||||||
views: ['panel1'],
|
|
||||||
id: 'group-1',
|
api.addPanel({
|
||||||
activeView: 'panel1',
|
id: 'panel2',
|
||||||
},
|
component: 'default',
|
||||||
size: 500,
|
position: { direction: 'right' },
|
||||||
},
|
});
|
||||||
{
|
|
||||||
type: 'branch',
|
api.addPanel({
|
||||||
data: [
|
id: 'panel3',
|
||||||
{
|
component: 'default',
|
||||||
type: 'leaf',
|
position: { direction: 'below' },
|
||||||
data: {
|
});
|
||||||
views: ['panel2', 'panel3'],
|
|
||||||
id: 'group-2',
|
const panel4 = api.addPanel({
|
||||||
activeView: 'panel3',
|
id: 'panel4',
|
||||||
},
|
component: 'default',
|
||||||
size: 500,
|
});
|
||||||
},
|
|
||||||
{
|
panel4.api.maximize();
|
||||||
type: 'leaf',
|
expect(panel4.api.isMaximized()).toBeTruthy();
|
||||||
data: {
|
|
||||||
views: ['panel4'],
|
const state = api.toJSON();
|
||||||
id: 'group-3',
|
expect(api.hasMaximizedGroup()).toBeTruthy();
|
||||||
activeView: 'panel4',
|
expect(panel4.api.isMaximized()).toBeTruthy();
|
||||||
},
|
|
||||||
size: 500,
|
api.clear();
|
||||||
},
|
expect(api.groups.length).toBe(0);
|
||||||
],
|
expect(api.panels.length).toBe(0);
|
||||||
size: 250,
|
|
||||||
},
|
api.fromJSON(state);
|
||||||
{
|
const newPanel4 = api.getPanel('panel4')!;
|
||||||
type: 'leaf',
|
expect(api.hasMaximizedGroup()).toBeTruthy();
|
||||||
data: {
|
expect(newPanel4.api.isMaximized()).toBeTruthy();
|
||||||
views: ['panel5'],
|
|
||||||
id: 'group-4',
|
expect(state).toEqual(api.toJSON());
|
||||||
activeView: 'panel5',
|
|
||||||
},
|
|
||||||
size: 250,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
size: 1000,
|
|
||||||
},
|
|
||||||
height: 1000,
|
|
||||||
width: 1000,
|
|
||||||
orientation: Orientation.VERTICAL,
|
|
||||||
},
|
|
||||||
panels: {
|
|
||||||
panel1: {
|
|
||||||
id: 'panel1',
|
|
||||||
contentComponent: 'default',
|
|
||||||
tabComponent: 'tab-default',
|
|
||||||
title: 'panel1',
|
|
||||||
},
|
|
||||||
panel2: {
|
|
||||||
id: 'panel2',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel2',
|
|
||||||
},
|
|
||||||
panel3: {
|
|
||||||
id: 'panel3',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel3',
|
|
||||||
renderer: 'onlyWhenVisible',
|
|
||||||
},
|
|
||||||
panel4: {
|
|
||||||
id: 'panel4',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel4',
|
|
||||||
renderer: 'always',
|
|
||||||
},
|
|
||||||
panel5: {
|
|
||||||
id: 'panel5',
|
|
||||||
contentComponent: 'default',
|
|
||||||
title: 'panel5',
|
|
||||||
minimumHeight: 100,
|
|
||||||
maximumHeight: 1000,
|
|
||||||
minimumWidth: 200,
|
|
||||||
maximumWidth: 2000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
DockviewMaximizedGroupChanged,
|
||||||
FloatingGroupOptions,
|
FloatingGroupOptions,
|
||||||
IDockviewComponent,
|
IDockviewComponent,
|
||||||
MovePanelEvent,
|
MovePanelEvent,
|
||||||
@ -898,7 +899,7 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
|||||||
this.component.exitMaximizedGroup();
|
this.component.exitMaximizedGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
get onDidMaximizedGroupChange(): Event<void> {
|
get onDidMaximizedGroupChange(): Event<DockviewMaximizedGroupChanged> {
|
||||||
return this.component.onDidMaximizedGroupChange;
|
return this.component.onDidMaximizedGroupChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +163,11 @@ export interface FloatingGroupOptionsInternal extends FloatingGroupOptions {
|
|||||||
skipActiveGroup?: boolean;
|
skipActiveGroup?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DockviewMaximizedGroupChanged {
|
||||||
|
group: DockviewGroupPanel;
|
||||||
|
isMaximized: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||||
readonly activePanel: IDockviewPanel | undefined;
|
readonly activePanel: IDockviewPanel | undefined;
|
||||||
readonly totalPanels: number;
|
readonly totalPanels: number;
|
||||||
@ -183,6 +188,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
|||||||
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
|
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
|
||||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent>;
|
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent>;
|
||||||
readonly onDidMovePanel: Event<MovePanelEvent>;
|
readonly onDidMovePanel: Event<MovePanelEvent>;
|
||||||
|
readonly onDidMaximizedGroupChange: Event<DockviewMaximizedGroupChanged>;
|
||||||
readonly options: DockviewComponentOptions;
|
readonly options: DockviewComponentOptions;
|
||||||
updateOptions(options: DockviewOptions): void;
|
updateOptions(options: DockviewOptions): void;
|
||||||
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
|
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
|
||||||
@ -275,6 +281,10 @@ export class DockviewComponent
|
|||||||
private readonly _onDidMovePanel = new Emitter<MovePanelEvent>();
|
private readonly _onDidMovePanel = new Emitter<MovePanelEvent>();
|
||||||
readonly onDidMovePanel = this._onDidMovePanel.event;
|
readonly onDidMovePanel = this._onDidMovePanel.event;
|
||||||
|
|
||||||
|
private readonly _onDidMaximizedGroupChange =
|
||||||
|
new Emitter<DockviewMaximizedGroupChanged>();
|
||||||
|
readonly onDidMaximizedGroupChange = this._onDidMaximizedGroupChange.event;
|
||||||
|
|
||||||
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
||||||
private readonly _popoutGroups: {
|
private readonly _popoutGroups: {
|
||||||
window: PopoutWindow;
|
window: PopoutWindow;
|
||||||
@ -395,6 +405,12 @@ export class DockviewComponent
|
|||||||
this._onDidActiveGroupChange.fire(event);
|
this._onDidActiveGroupChange.fire(event);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
this.onDidMaximizedChange((event) => {
|
||||||
|
this._onDidMaximizedGroupChange.fire({
|
||||||
|
group: event.panel,
|
||||||
|
isMaximized: event.isMaximized,
|
||||||
|
});
|
||||||
|
}),
|
||||||
Event.any(
|
Event.any(
|
||||||
this.onDidAdd,
|
this.onDidAdd,
|
||||||
this.onDidRemove
|
this.onDidRemove
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { Emitter, Event, AsapEvent } from '../events';
|
import { Emitter, Event, AsapEvent } from '../events';
|
||||||
import { getGridLocation, Gridview, IGridView } from './gridview';
|
import {
|
||||||
|
getGridLocation,
|
||||||
|
Gridview,
|
||||||
|
IGridView,
|
||||||
|
MaximizedViewChanged,
|
||||||
|
} from './gridview';
|
||||||
import { Position } from '../dnd/droptarget';
|
import { Position } from '../dnd/droptarget';
|
||||||
import { Disposable, IDisposable, IValueDisposable } from '../lifecycle';
|
import { Disposable, IDisposable, IValueDisposable } from '../lifecycle';
|
||||||
import { sequentialNumberGenerator } from '../math';
|
import { sequentialNumberGenerator } from '../math';
|
||||||
@ -8,6 +13,7 @@ import { IPanel } from '../panel/types';
|
|||||||
import { MovementOptions2 } from '../dockview/options';
|
import { MovementOptions2 } from '../dockview/options';
|
||||||
import { Resizable } from '../resizable';
|
import { Resizable } from '../resizable';
|
||||||
import { Classnames } from '../dom';
|
import { Classnames } from '../dom';
|
||||||
|
import { IGridviewComponent } from './gridviewComponent';
|
||||||
|
|
||||||
const nextLayoutId = sequentialNumberGenerator();
|
const nextLayoutId = sequentialNumberGenerator();
|
||||||
|
|
||||||
@ -29,6 +35,11 @@ export function toTarget(direction: Direction): Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MaximizedChanged<T extends IGridPanelView> {
|
||||||
|
panel: T;
|
||||||
|
isMaximized: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BaseGridOptions {
|
export interface BaseGridOptions {
|
||||||
readonly proportionalLayout: boolean;
|
readonly proportionalLayout: boolean;
|
||||||
readonly orientation: Orientation;
|
readonly orientation: Orientation;
|
||||||
@ -56,6 +67,8 @@ export interface IBaseGrid<T extends IGridPanelView> extends IDisposable {
|
|||||||
readonly activeGroup: T | undefined;
|
readonly activeGroup: T | undefined;
|
||||||
readonly size: number;
|
readonly size: number;
|
||||||
readonly groups: T[];
|
readonly groups: T[];
|
||||||
|
readonly onDidMaximizedChange: Event<MaximizedChanged<T>>;
|
||||||
|
readonly onDidLayoutChange: Event<void>;
|
||||||
getPanel(id: string): T | undefined;
|
getPanel(id: string): T | undefined;
|
||||||
toJSON(): object;
|
toJSON(): object;
|
||||||
fromJSON(data: any): void;
|
fromJSON(data: any): void;
|
||||||
@ -67,8 +80,6 @@ export interface IBaseGrid<T extends IGridPanelView> extends IDisposable {
|
|||||||
isMaximizedGroup(panel: T): boolean;
|
isMaximizedGroup(panel: T): boolean;
|
||||||
exitMaximizedGroup(): void;
|
exitMaximizedGroup(): void;
|
||||||
hasMaximizedGroup(): boolean;
|
hasMaximizedGroup(): boolean;
|
||||||
readonly onDidMaximizedGroupChange: Event<void>;
|
|
||||||
readonly onDidLayoutChange: Event<void>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BaseGrid<T extends IGridPanelView>
|
export abstract class BaseGrid<T extends IGridPanelView>
|
||||||
@ -87,6 +98,10 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
private readonly _onDidAdd = new Emitter<T>();
|
private readonly _onDidAdd = new Emitter<T>();
|
||||||
readonly onDidAdd: Event<T> = this._onDidAdd.event;
|
readonly onDidAdd: Event<T> = this._onDidAdd.event;
|
||||||
|
|
||||||
|
private readonly _onDidMaximizedChange = new Emitter<MaximizedChanged<T>>();
|
||||||
|
readonly onDidMaximizedChange: Event<MaximizedChanged<T>> =
|
||||||
|
this._onDidMaximizedChange.event;
|
||||||
|
|
||||||
private readonly _onDidActiveChange = new Emitter<T | undefined>();
|
private readonly _onDidActiveChange = new Emitter<T | undefined>();
|
||||||
readonly onDidActiveChange: Event<T | undefined> =
|
readonly onDidActiveChange: Event<T | undefined> =
|
||||||
this._onDidActiveChange.event;
|
this._onDidActiveChange.event;
|
||||||
@ -171,6 +186,12 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
this.layout(0, 0, true); // set some elements height/widths
|
this.layout(0, 0, true); // set some elements height/widths
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
|
this.gridview.onDidMaximizedNodeChange((event) => {
|
||||||
|
this._onDidMaximizedChange.fire({
|
||||||
|
panel: event.view as T,
|
||||||
|
isMaximized: event.isMaximized,
|
||||||
|
});
|
||||||
|
}),
|
||||||
this.gridview.onDidViewVisibilityChange(() =>
|
this.gridview.onDidViewVisibilityChange(() =>
|
||||||
this._onDidViewVisibilityChangeMicroTaskQueue.fire()
|
this._onDidViewVisibilityChangeMicroTaskQueue.fire()
|
||||||
),
|
),
|
||||||
@ -250,10 +271,6 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
return this.gridview.hasMaximizedView();
|
return this.gridview.hasMaximizedView();
|
||||||
}
|
}
|
||||||
|
|
||||||
get onDidMaximizedGroupChange(): Event<void> {
|
|
||||||
return this.gridview.onDidMaximizedNodeChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected doAddGroup(
|
protected doAddGroup(
|
||||||
group: T,
|
group: T,
|
||||||
location: number[] = [0],
|
location: number[] = [0],
|
||||||
|
@ -265,11 +265,21 @@ export interface IViewDeserializer {
|
|||||||
fromJSON: (data: ISerializedLeafNode) => IGridView;
|
fromJSON: (data: ISerializedLeafNode) => IGridView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SerializedNodeDescriptor {
|
||||||
|
location: number[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface SerializedGridview<T> {
|
export interface SerializedGridview<T> {
|
||||||
root: SerializedGridObject<T>;
|
root: SerializedGridObject<T>;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
orientation: Orientation;
|
orientation: Orientation;
|
||||||
|
maximizedNode?: SerializedNodeDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MaximizedViewChanged {
|
||||||
|
view: IGridView;
|
||||||
|
isMaximized: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Gridview implements IDisposable {
|
export class Gridview implements IDisposable {
|
||||||
@ -293,7 +303,8 @@ export class Gridview implements IDisposable {
|
|||||||
private readonly _onDidViewVisibilityChange = new Emitter<void>();
|
private readonly _onDidViewVisibilityChange = new Emitter<void>();
|
||||||
readonly onDidViewVisibilityChange = this._onDidViewVisibilityChange.event;
|
readonly onDidViewVisibilityChange = this._onDidViewVisibilityChange.event;
|
||||||
|
|
||||||
private readonly _onDidMaximizedNodeChange = new Emitter<void>();
|
private readonly _onDidMaximizedNodeChange =
|
||||||
|
new Emitter<MaximizedViewChanged>();
|
||||||
readonly onDidMaximizedNodeChange = this._onDidMaximizedNodeChange.event;
|
readonly onDidMaximizedNodeChange = this._onDidMaximizedNodeChange.event;
|
||||||
|
|
||||||
public get length(): number {
|
public get length(): number {
|
||||||
@ -395,6 +406,8 @@ export class Gridview implements IDisposable {
|
|||||||
this.exitMaximizedView();
|
this.exitMaximizedView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serializeBranchNode(this.getView(), this.orientation);
|
||||||
|
|
||||||
const hiddenOnMaximize: LeafNode[] = [];
|
const hiddenOnMaximize: LeafNode[] = [];
|
||||||
|
|
||||||
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
|
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
|
||||||
@ -416,7 +429,10 @@ export class Gridview implements IDisposable {
|
|||||||
|
|
||||||
hideAllViewsBut(this.root, node);
|
hideAllViewsBut(this.root, node);
|
||||||
this._maximizedNode = { leaf: node, hiddenOnMaximize };
|
this._maximizedNode = { leaf: node, hiddenOnMaximize };
|
||||||
this._onDidMaximizedNodeChange.fire();
|
this._onDidMaximizedNodeChange.fire({
|
||||||
|
view: node.view,
|
||||||
|
isMaximized: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exitMaximizedView(): void {
|
exitMaximizedView(): void {
|
||||||
@ -441,27 +457,60 @@ export class Gridview implements IDisposable {
|
|||||||
|
|
||||||
showViewsInReverseOrder(this.root);
|
showViewsInReverseOrder(this.root);
|
||||||
|
|
||||||
|
const tmp = this._maximizedNode.leaf;
|
||||||
this._maximizedNode = undefined;
|
this._maximizedNode = undefined;
|
||||||
this._onDidMaximizedNodeChange.fire();
|
this._onDidMaximizedNodeChange.fire({
|
||||||
|
view: tmp.view,
|
||||||
|
isMaximized: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public serialize(): SerializedGridview<any> {
|
public serialize(): SerializedGridview<any> {
|
||||||
|
const maximizedView = this.maximizedView();
|
||||||
|
|
||||||
|
let maxmizedViewLocation: number[] | undefined;
|
||||||
|
|
||||||
|
if (maximizedView) {
|
||||||
|
/**
|
||||||
|
* The minimum information we can get away with in order to serialize a maxmized view is it's location within the grid
|
||||||
|
* which is represented as a branch of indices
|
||||||
|
*/
|
||||||
|
maxmizedViewLocation = getGridLocation(maximizedView.element);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hasMaximizedView()) {
|
if (this.hasMaximizedView()) {
|
||||||
/**
|
/**
|
||||||
* do not persist maximized view state
|
* the saved layout cannot be in its maxmized state otherwise all of the underlying
|
||||||
* firstly exit any maximized views to ensure the correct dimensions are persisted
|
* view dimensions will be wrong
|
||||||
|
*
|
||||||
|
* To counteract this we temporaily remove the maximized view to compute the serialized output
|
||||||
|
* of the grid before adding back the maxmized view as to not alter the layout from the users
|
||||||
|
* perspective when `.toJSON()` is called
|
||||||
*/
|
*/
|
||||||
this.exitMaximizedView();
|
this.exitMaximizedView();
|
||||||
}
|
}
|
||||||
|
|
||||||
const root = serializeBranchNode(this.getView(), this.orientation);
|
const root = serializeBranchNode(this.getView(), this.orientation);
|
||||||
|
|
||||||
return {
|
const resullt: SerializedGridview<any> = {
|
||||||
root,
|
root,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
orientation: this.orientation,
|
orientation: this.orientation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (maxmizedViewLocation) {
|
||||||
|
resullt.maximizedNode = {
|
||||||
|
location: maxmizedViewLocation,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maximizedView) {
|
||||||
|
// replace any maximzied view that was removed for serialization purposes
|
||||||
|
this.maximizeView(maximizedView);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resullt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
@ -502,6 +551,24 @@ export class Gridview implements IDisposable {
|
|||||||
deserializer,
|
deserializer,
|
||||||
height
|
height
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserialied layout must be positioned through this.layout(...)
|
||||||
|
* before any maximizedNode can be positioned
|
||||||
|
*/
|
||||||
|
this.layout(json.width, json.height);
|
||||||
|
|
||||||
|
if (json.maximizedNode) {
|
||||||
|
const location = json.maximizedNode.location;
|
||||||
|
|
||||||
|
const [_, node] = this.getNode(location);
|
||||||
|
|
||||||
|
if (!(node instanceof LeafNode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maximizeView(node.view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _deserialize(
|
private _deserialize(
|
||||||
|
@ -206,6 +206,12 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
addLogLine(`Panel Moved ${event.panel.id}`);
|
addLogLine(`Panel Moved ${event.panel.id}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
event.api.onDidMaximizedGroupChange((event) => {
|
||||||
|
addLogLine(
|
||||||
|
`Group Maximized Changed ${event.view.id} [${event.isMaximized}]`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
event.api.onDidRemoveGroup((event) => {
|
event.api.onDidRemoveGroup((event) => {
|
||||||
setGroups((_) => {
|
setGroups((_) => {
|
||||||
const next = [..._];
|
const next = [..._];
|
||||||
@ -318,6 +324,15 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
engineering
|
engineering
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
{showLogs && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setLogLines([]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">undo</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowLogs(!showLogs);
|
setShowLogs(!showLogs);
|
||||||
|
@ -112,11 +112,10 @@ export const GridActions = (props: {
|
|||||||
|
|
||||||
const onSave = () => {
|
const onSave = () => {
|
||||||
if (props.api) {
|
if (props.api) {
|
||||||
console.log(props.api.toJSON());
|
const state = props.api.toJSON();
|
||||||
localStorage.setItem(
|
console.log(state);
|
||||||
'dv-demo-state',
|
|
||||||
JSON.stringify(props.api.toJSON())
|
localStorage.setItem('dv-demo-state', JSON.stringify(state));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user