mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 23:18:11 +08:00
Add support for dragging panel tabs docked into other panel tab bars (#4006)
* Add support for dragging panel tabs docked into other panel tab bars * Fix terminology * Add Group suffix to PanelGroupId enums variants * Code review
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { writable } from "svelte/store";
|
||||
import type { Writable } from "svelte/store";
|
||||
|
||||
export type PanelDragState = {
|
||||
active: boolean;
|
||||
sourcePanelId: string | undefined;
|
||||
draggedTabLabel: string | undefined;
|
||||
sourceTabIndex: number;
|
||||
// Which panel's tab bar the pointer is currently hovering over (undefined if none)
|
||||
hoverTargetPanelId: string | undefined;
|
||||
hoverInsertionIndex: number | undefined;
|
||||
hoverInsertionMarkerLeft: number | undefined;
|
||||
};
|
||||
|
||||
const initialState: PanelDragState = {
|
||||
active: false,
|
||||
sourcePanelId: undefined,
|
||||
draggedTabLabel: undefined,
|
||||
sourceTabIndex: 0,
|
||||
hoverTargetPanelId: undefined,
|
||||
hoverInsertionIndex: undefined,
|
||||
hoverInsertionMarkerLeft: undefined,
|
||||
};
|
||||
|
||||
// Store state persisted across HMR to maintain reactive subscriptions in the component tree
|
||||
const store: Writable<PanelDragState> = import.meta.hot?.data?.store || writable<PanelDragState>(initialState);
|
||||
if (import.meta.hot) import.meta.hot.data.store = store;
|
||||
|
||||
export const panelDrag = store;
|
||||
|
||||
export function startCrossPanelDrag(sourcePanelId: string, draggedTabLabel: string, sourceTabIndex: number) {
|
||||
store.update((state) => {
|
||||
state.active = true;
|
||||
state.sourcePanelId = sourcePanelId;
|
||||
state.draggedTabLabel = draggedTabLabel;
|
||||
state.sourceTabIndex = sourceTabIndex;
|
||||
return state;
|
||||
});
|
||||
}
|
||||
|
||||
export function endCrossPanelDrag() {
|
||||
store.update((state) => {
|
||||
state.active = false;
|
||||
state.sourcePanelId = undefined;
|
||||
state.draggedTabLabel = undefined;
|
||||
state.sourceTabIndex = 0;
|
||||
state.hoverTargetPanelId = undefined;
|
||||
state.hoverInsertionIndex = undefined;
|
||||
state.hoverInsertionMarkerLeft = undefined;
|
||||
return state;
|
||||
});
|
||||
}
|
||||
|
||||
export function updateCrossPanelHover(hoverTargetPanelId: string | undefined, hoverInsertionIndex: number | undefined, hoverInsertionMarkerLeft: number | undefined) {
|
||||
store.update((state) => {
|
||||
state.hoverTargetPanelId = hoverTargetPanelId;
|
||||
state.hoverInsertionIndex = hoverInsertionIndex;
|
||||
state.hoverInsertionMarkerLeft = hoverInsertionMarkerLeft;
|
||||
return state;
|
||||
});
|
||||
}
|
||||
@@ -4,25 +4,36 @@ import type { SubscriptionsRouter } from "/src/subscriptions-router";
|
||||
import { downloadFile, downloadFileBlob, upload } from "/src/utility-functions/files";
|
||||
import { storeDocumentTabOrder } from "/src/utility-functions/persistence";
|
||||
import { rasterizeSVG } from "/src/utility-functions/rasterization";
|
||||
import type { EditorWrapper, OpenDocument } from "/wrapper/pkg/graphite_wasm_wrapper";
|
||||
import type { EditorWrapper, OpenDocument, PanelType } from "/wrapper/pkg/graphite_wasm_wrapper";
|
||||
|
||||
export type PortfolioStore = ReturnType<typeof createPortfolioStore>;
|
||||
|
||||
export type PanelGroupState = {
|
||||
tabs: PanelType[];
|
||||
activeTabIndex: number;
|
||||
};
|
||||
|
||||
export type WorkspacePanelLayout = {
|
||||
propertiesGroup: PanelGroupState;
|
||||
layersGroup: PanelGroupState;
|
||||
dataGroup: PanelGroupState;
|
||||
};
|
||||
|
||||
type PortfolioStoreState = {
|
||||
unsaved: boolean;
|
||||
documents: OpenDocument[];
|
||||
activeDocumentIndex: number;
|
||||
dataPanelOpen: boolean;
|
||||
propertiesPanelOpen: boolean;
|
||||
layersPanelOpen: boolean;
|
||||
panelLayout: WorkspacePanelLayout;
|
||||
};
|
||||
const initialState: PortfolioStoreState = {
|
||||
unsaved: false,
|
||||
documents: [],
|
||||
activeDocumentIndex: 0,
|
||||
dataPanelOpen: false,
|
||||
propertiesPanelOpen: true,
|
||||
layersPanelOpen: true,
|
||||
panelLayout: {
|
||||
propertiesGroup: { tabs: ["Properties"], activeTabIndex: 0 },
|
||||
layersGroup: { tabs: ["Layers"], activeTabIndex: 0 },
|
||||
dataGroup: { tabs: [], activeTabIndex: 0 },
|
||||
},
|
||||
};
|
||||
|
||||
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
|
||||
@@ -103,23 +114,15 @@ export function createPortfolioStore(subscriptions: SubscriptionsRouter, editor:
|
||||
}
|
||||
});
|
||||
|
||||
subscriptions.subscribeFrontendMessage("UpdateDataPanelState", async (data) => {
|
||||
update((state) => {
|
||||
state.dataPanelOpen = data.open;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
subscriptions.subscribeFrontendMessage("UpdateWorkspacePanelLayout", (data) => {
|
||||
// Coerce activeTabIndex from BigInt (produced by serde_wasm_bindgen for usize) to number
|
||||
const layout = data.panelLayout;
|
||||
layout.propertiesGroup.activeTabIndex = Number(layout.propertiesGroup.activeTabIndex);
|
||||
layout.layersGroup.activeTabIndex = Number(layout.layersGroup.activeTabIndex);
|
||||
layout.dataGroup.activeTabIndex = Number(layout.dataGroup.activeTabIndex);
|
||||
|
||||
subscriptions.subscribeFrontendMessage("UpdatePropertiesPanelState", async (data) => {
|
||||
update((state) => {
|
||||
state.propertiesPanelOpen = data.open;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
|
||||
subscriptions.subscribeFrontendMessage("UpdateLayersPanelState", async (data) => {
|
||||
update((state) => {
|
||||
state.layersPanelOpen = data.open;
|
||||
state.panelLayout = layout;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
@@ -139,7 +142,5 @@ export function destroyPortfolioStore() {
|
||||
subscriptions.unsubscribeFrontendMessage("TriggerSaveDocument");
|
||||
subscriptions.unsubscribeFrontendMessage("TriggerSaveFile");
|
||||
subscriptions.unsubscribeFrontendMessage("TriggerExportImage");
|
||||
subscriptions.unsubscribeFrontendMessage("UpdateDataPanelState");
|
||||
subscriptions.unsubscribeFrontendMessage("UpdatePropertiesPanelState");
|
||||
subscriptions.unsubscribeFrontendMessage("UpdateLayersPanelState");
|
||||
subscriptions.unsubscribeFrontendMessage("UpdateWorkspacePanelLayout");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user