work in progress

This commit is contained in:
mathuo 2023-07-24 19:47:04 +01:00
parent 8833a973b9
commit 2aa700bca0
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
6 changed files with 96 additions and 59 deletions

View File

@ -10,7 +10,7 @@ export abstract class DragHandler extends CompositeDisposable {
private readonly dataDisposable = new MutableDisposable(); private readonly dataDisposable = new MutableDisposable();
private readonly pointerEventsDisposable = new MutableDisposable(); private readonly pointerEventsDisposable = new MutableDisposable();
private readonly _onDragStart = new Emitter<void>(); private readonly _onDragStart = new Emitter<DragEvent>();
readonly onDragStart = this._onDragStart.event; readonly onDragStart = this._onDragStart.event;
constructor(protected readonly el: HTMLElement) { constructor(protected readonly el: HTMLElement) {
@ -35,7 +35,9 @@ export abstract class DragHandler extends CompositeDisposable {
this.addDisposables( this.addDisposables(
this._onDragStart, this._onDragStart,
addDisposableListener(this.el, 'dragstart', (event) => { addDisposableListener(this.el, 'dragstart', (event) => {
if (this.isCancelled(event)) { this._onDragStart.fire(event);
if (event.defaultPrevented || this.isCancelled(event)) {
event.preventDefault(); event.preventDefault();
return; return;
} }

View File

@ -11,9 +11,37 @@ import { DockviewDropTargets, ITabRenderer } from '../../types';
import { DockviewGroupPanel } from '../../dockviewGroupPanel'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget'; import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget';
import { DragHandler } from '../../../dnd/abstractDragHandler'; import { DragHandler } from '../../../dnd/abstractDragHandler';
import { IDockviewPanel } from '../../dockviewPanel';
class TabDragHandler extends DragHandler {
private readonly panelTransfer =
LocalSelectionTransfer.getInstance<PanelTransfer>();
constructor(
element: HTMLElement,
private readonly accessor: DockviewComponent,
private readonly group: DockviewGroupPanel,
private readonly panel: IDockviewPanel
) {
super(element);
}
getData(): IDisposable {
this.panelTransfer.setData(
[new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)],
PanelTransfer.prototype
);
return {
dispose: () => {
this.panelTransfer.clearData(PanelTransfer.prototype);
},
};
}
}
export interface ITab extends IDisposable { export interface ITab extends IDisposable {
readonly panelId: string; readonly panel: IDockviewPanel;
readonly element: HTMLElement; readonly element: HTMLElement;
setContent: (element: ITabRenderer) => void; setContent: (element: ITabRenderer) => void;
onChanged: Event<MouseEvent>; onChanged: Event<MouseEvent>;
@ -24,7 +52,7 @@ export interface ITab extends IDisposable {
export class Tab extends CompositeDisposable implements ITab { export class Tab extends CompositeDisposable implements ITab {
private readonly _element: HTMLElement; private readonly _element: HTMLElement;
private readonly droptarget: Droptarget; private readonly droptarget: Droptarget;
private content?: ITabRenderer; private content: ITabRenderer | undefined = undefined;
private readonly _onChanged = new Emitter<MouseEvent>(); private readonly _onChanged = new Emitter<MouseEvent>();
readonly onChanged: Event<MouseEvent> = this._onChanged.event; readonly onChanged: Event<MouseEvent> = this._onChanged.event;
@ -32,12 +60,15 @@ export class Tab extends CompositeDisposable implements ITab {
private readonly _onDropped = new Emitter<DroptargetEvent>(); private readonly _onDropped = new Emitter<DroptargetEvent>();
readonly onDrop: Event<DroptargetEvent> = this._onDropped.event; readonly onDrop: Event<DroptargetEvent> = this._onDropped.event;
private readonly _onDragStart = new Emitter<DragEvent>();
readonly onDragStart = this._onDragStart.event;
public get element(): HTMLElement { public get element(): HTMLElement {
return this._element; return this._element;
} }
constructor( constructor(
public readonly panelId: string, public readonly panel: IDockviewPanel,
private readonly accessor: DockviewComponent, private readonly accessor: DockviewComponent,
private readonly group: DockviewGroupPanel private readonly group: DockviewGroupPanel
) { ) {
@ -50,38 +81,11 @@ export class Tab extends CompositeDisposable implements ITab {
toggleClass(this.element, 'inactive-tab', true); toggleClass(this.element, 'inactive-tab', true);
this.addDisposables( const dragHandler = new TabDragHandler(
this._onChanged, this._element,
this._onDropped, this.accessor,
new (class Handler extends DragHandler { this.group,
private readonly panelTransfer = this.panel
LocalSelectionTransfer.getInstance<PanelTransfer>();
getData(): IDisposable {
this.panelTransfer.setData(
[new PanelTransfer(accessor.id, group.id, panelId)],
PanelTransfer.prototype
);
return {
dispose: () => {
this.panelTransfer.clearData(
PanelTransfer.prototype
);
},
};
}
})(this._element)
);
this.addDisposables(
addDisposableListener(this._element, 'mousedown', (event) => {
if (event.defaultPrevented) {
return;
}
this._onChanged.fire(event);
})
); );
this.droptarget = new Droptarget(this._element, { this.droptarget = new Droptarget(this._element, {
@ -102,7 +106,7 @@ export class Tab extends CompositeDisposable implements ITab {
return false; return false;
} }
return this.panelId !== data.panelId; return this.panel.id !== data.panelId;
} }
return this.group.model.canDisplayOverlay( return this.group.model.canDisplayOverlay(
@ -114,6 +118,20 @@ export class Tab extends CompositeDisposable implements ITab {
}); });
this.addDisposables( this.addDisposables(
this._onChanged,
this._onDropped,
this._onDragStart,
dragHandler.onDragStart((event) => {
this._onDragStart.fire(event);
}),
dragHandler,
addDisposableListener(this._element, 'mousedown', (event) => {
if (event.defaultPrevented) {
return;
}
this._onChanged.fire(event);
}),
this.droptarget.onDrop((event) => { this.droptarget.onDrop((event) => {
this._onDropped.fire(event); this._onDropped.fire(event);
}), }),

View File

@ -16,13 +16,20 @@ export interface TabDropIndexEvent {
readonly index: number; readonly index: number;
} }
export interface TabDragEvent {
readonly nativeEvent: DragEvent;
readonly panel?: IDockviewPanel;
}
export interface ITabsContainer extends IDisposable { export interface ITabsContainer extends IDisposable {
readonly element: HTMLElement; readonly element: HTMLElement;
readonly panels: string[]; readonly panels: string[];
readonly size: number; readonly size: number;
hidden: boolean;
delete: (id: string) => void; delete: (id: string) => void;
indexOf: (id: string) => number; indexOf: (id: string) => number;
onDrop: Event<TabDropIndexEvent>; onDrop: Event<TabDropIndexEvent>;
onDragStart: Event<TabDragEvent>;
setActive: (isGroupActive: boolean) => void; setActive: (isGroupActive: boolean) => void;
setActivePanel: (panel: IDockviewPanel) => void; setActivePanel: (panel: IDockviewPanel) => void;
isActive: (tab: ITab) => boolean; isActive: (tab: ITab) => boolean;
@ -30,7 +37,6 @@ export interface ITabsContainer extends IDisposable {
openPanel: (panel: IDockviewPanel, index?: number) => void; openPanel: (panel: IDockviewPanel, index?: number) => void;
setRightActionsElement(element: HTMLElement | undefined): void; setRightActionsElement(element: HTMLElement | undefined): void;
setLeftActionsElement(element: HTMLElement | undefined): void; setLeftActionsElement(element: HTMLElement | undefined): void;
hidden: boolean;
show(): void; show(): void;
hide(): void; hide(): void;
} }
@ -55,8 +61,11 @@ export class TabsContainer
private readonly _onDrop = new Emitter<TabDropIndexEvent>(); private readonly _onDrop = new Emitter<TabDropIndexEvent>();
readonly onDrop: Event<TabDropIndexEvent> = this._onDrop.event; readonly onDrop: Event<TabDropIndexEvent> = this._onDrop.event;
private readonly _onDragStart = new Emitter<TabDragEvent>();
readonly onDragStart: Event<TabDragEvent> = this._onDragStart.event;
get panels(): string[] { get panels(): string[] {
return this.tabs.map((_) => _.value.panelId); return this.tabs.map((_) => _.value.panel.id);
} }
get size(): number { get size(): number {
@ -122,7 +131,7 @@ export class TabsContainer
} }
public indexOf(id: string): number { public indexOf(id: string): number {
return this.tabs.findIndex((tab) => tab.value.panelId === id); return this.tabs.findIndex((tab) => tab.value.panel.id === id);
} }
constructor( constructor(
@ -131,7 +140,7 @@ export class TabsContainer
) { ) {
super(); super();
this.addDisposables(this._onDrop); this.addDisposables(this._onDrop, this._onDragStart);
this._element = document.createElement('div'); this._element = document.createElement('div');
this._element.className = 'tabs-and-actions-container'; this._element.className = 'tabs-and-actions-container';
@ -260,7 +269,7 @@ export class TabsContainer
} }
public delete(id: string): void { public delete(id: string): void {
const index = this.tabs.findIndex((tab) => tab.value.panelId === id); const index = this.tabs.findIndex((tab) => tab.value.panel.id === id);
const tabToRemove = this.tabs.splice(index, 1)[0]; const tabToRemove = this.tabs.splice(index, 1)[0];
@ -273,7 +282,7 @@ export class TabsContainer
public setActivePanel(panel: IDockviewPanel): void { public setActivePanel(panel: IDockviewPanel): void {
this.tabs.forEach((tab) => { this.tabs.forEach((tab) => {
const isActivePanel = panel.id === tab.value.panelId; const isActivePanel = panel.id === tab.value.panel.id;
tab.value.setActive(isActivePanel); tab.value.setActive(isActivePanel);
}); });
} }
@ -282,17 +291,20 @@ export class TabsContainer
panel: IDockviewPanel, panel: IDockviewPanel,
index: number = this.tabs.length index: number = this.tabs.length
): void { ): void {
if (this.tabs.find((tab) => tab.value.panelId === panel.id)) { if (this.tabs.find((tab) => tab.value.panel.id === panel.id)) {
return; return;
} }
const tabToAdd = new Tab(panel.id, this.accessor, this.group); const tab = new Tab(panel, this.accessor, this.group);
if (!panel.view?.tab) { if (!panel.view?.tab) {
throw new Error('invalid header component'); throw new Error('invalid header component');
} }
tabToAdd.setContent(panel.view.tab); tab.setContent(panel.view.tab);
const disposable = CompositeDisposable.from( const disposable = new CompositeDisposable(
tabToAdd.onChanged((event) => { tab.onDragStart((event) => {
this._onDragStart.fire({ nativeEvent: event, panel });
}),
tab.onChanged((event) => {
const isFloatingGroupsEnabled = const isFloatingGroupsEnabled =
!this.accessor.options.disableFloatingGroups; !this.accessor.options.disableFloatingGroups;
@ -306,10 +318,9 @@ export class TabsContainer
) { ) {
event.preventDefault(); event.preventDefault();
const panel = this.accessor.getGroupPanel(tabToAdd.panelId); const panel = this.accessor.getGroupPanel(tab.panel.id);
const { top, left } = const { top, left } = tab.element.getBoundingClientRect();
tabToAdd.element.getBoundingClientRect();
const { top: rootTop, left: rootLeft } = const { top: rootTop, left: rootLeft } =
this.accessor.element.getBoundingClientRect(); this.accessor.element.getBoundingClientRect();
@ -338,15 +349,15 @@ export class TabsContainer
skipFocus: alreadyFocused, skipFocus: alreadyFocused,
}); });
}), }),
tabToAdd.onDrop((event) => { tab.onDrop((event) => {
this._onDrop.fire({ this._onDrop.fire({
event: event.nativeEvent, event: event.nativeEvent,
index: this.tabs.findIndex((x) => x.value === tabToAdd), index: this.tabs.findIndex((x) => x.value === tab),
}); });
}) })
); );
const value: IValueDisposable<ITab> = { value: tabToAdd, disposable }; const value: IValueDisposable<ITab> = { value: tab, disposable };
this.addTab(value, index); this.addTab(value, index);
} }

View File

@ -1157,6 +1157,9 @@ export class DockviewComponent
if (!this._groups.has(view.id)) { if (!this._groups.has(view.id)) {
const disposable = new CompositeDisposable( const disposable = new CompositeDisposable(
view.model.onDragStart((event) => {
this.onDragStart(event);
}),
view.model.onMove((event) => { view.model.onMove((event) => {
const { groupId, itemId, target, index } = event; const { groupId, itemId, target, index } = event;
this.moveGroupOrPanel(view, groupId, itemId, target, index); this.moveGroupOrPanel(view, groupId, itemId, target, index);

View File

@ -13,6 +13,7 @@ import {
} from './components/panel/content'; } from './components/panel/content';
import { import {
ITabsContainer, ITabsContainer,
TabDragEvent,
TabsContainer, TabsContainer,
} from './components/titlebar/tabsContainer'; } from './components/titlebar/tabsContainer';
import { DockviewDropTargets, IWatermarkRenderer } from './types'; import { DockviewDropTargets, IWatermarkRenderer } from './types';
@ -158,6 +159,9 @@ export class DockviewGroupPanelModel
private readonly _onDidDrop = new Emitter<GroupviewDropEvent>(); private readonly _onDidDrop = new Emitter<GroupviewDropEvent>();
readonly onDidDrop: Event<GroupviewDropEvent> = this._onDidDrop.event; readonly onDidDrop: Event<GroupviewDropEvent> = this._onDidDrop.event;
private readonly _onDragStart = new Emitter<TabDragEvent>();
readonly onDragStart: Event<TabDragEvent> = this._onDragStart.event;
private readonly _onDidAddPanel = new Emitter<GroupviewChangeEvent>(); private readonly _onDidAddPanel = new Emitter<GroupviewChangeEvent>();
readonly onDidAddPanel: Event<GroupviewChangeEvent> = readonly onDidAddPanel: Event<GroupviewChangeEvent> =
this._onDidAddPanel.event; this._onDidAddPanel.event;
@ -306,6 +310,9 @@ export class DockviewGroupPanelModel
this.locked = !!options.locked; this.locked = !!options.locked;
this.addDisposables( this.addDisposables(
this.tabsContainer.onDragStart((event) => {
this._onDragStart.fire(event);
}),
this.tabsContainer.onDrop((event) => { this.tabsContainer.onDrop((event) => {
this.handleDropEvent(event.event, 'center', event.index); this.handleDropEvent(event.event, 'center', event.index);
}), }),

View File

@ -23,10 +23,6 @@ export class CompositeDisposable {
return this._isDisposed; return this._isDisposed;
} }
public static from(...args: IDisposable[]): CompositeDisposable {
return new CompositeDisposable(...args);
}
constructor(...args: IDisposable[]) { constructor(...args: IDisposable[]) {
this._disposables = args; this._disposables = args;
} }