Files
gpx.studio/website/src/lib/components/toolbar/tools/waypoint/waypoint.ts
T

108 lines
3.5 KiB
TypeScript
Raw Normal View History

2026-10-04 17:09:41 +02:00
import { get, writable } from 'svelte/store';
import { engine, type WaypointDetails } from '$lib/engine';
2026-10-11 11:18:36 +02:00
import { settings } from '$lib/state/settings';
2025-10-05 19:34:05 +02:00
2026-10-04 17:09:41 +02:00
export type SelectedWaypoint = {
fileId: string;
id: string;
/** The data of the waypoint, kept up to date with the file. */
waypoint: WaypointDetails;
};
/**
* The waypoint that the waypoint tool is about: the selected one when the file tree is shown and
* a single waypoint is selected, or the one that was set explicitly (clicking a waypoint of the
* map) until the selection changes to something else than its file or itself (that is what
* clicking it selects, depending on the view, and the selection may arrive after it is set).
*/
2025-10-05 19:34:05 +02:00
export class WaypointSelection {
2026-10-04 17:09:41 +02:00
private _selection = writable<SelectedWaypoint | undefined>(undefined);
2025-10-18 16:10:08 +02:00
private _fileUnsubscribe: (() => void) | undefined;
2026-10-04 17:09:41 +02:00
private _explicit: { fileId: string; id: string } | undefined;
2025-10-05 19:34:05 +02:00
constructor() {
2026-10-04 17:09:41 +02:00
settings.treeFileView.subscribe(() => this.updateFromSelection());
engine.selection.subscribe(() => this.updateFromSelection());
2025-10-17 23:54:45 +02:00
}
2025-10-18 16:10:08 +02:00
subscribe(
2026-10-04 17:09:41 +02:00
run: (value: SelectedWaypoint | undefined) => void,
invalidate?: (value?: SelectedWaypoint | undefined) => void
2025-10-18 16:10:08 +02:00
) {
return this._selection.subscribe(run, invalidate);
}
2026-10-04 17:09:41 +02:00
/** Sets the waypoint, whatever the selection is. */
set(target: { fileId: string; id: string } | undefined) {
this._explicit = target;
this.track(target);
2025-10-18 16:10:08 +02:00
}
2026-10-04 17:09:41 +02:00
updateFromSelection() {
const selection = get(engine.selection);
const explicit = this._explicit;
if (
explicit &&
((selection.type === 'file' &&
selection.fileIds.length === 1 &&
selection.fileIds[0] === explicit.fileId) ||
(selection.type === 'waypoint' &&
selection.fileId === explicit.fileId &&
selection.waypointIds.length === 1 &&
selection.waypointIds[0] === explicit.id))
) {
return;
}
this._explicit = undefined;
if (
get(settings.treeFileView) &&
selection.type === 'waypoint' &&
selection.waypointIds.length === 1
) {
this.track({ fileId: selection.fileId, id: selection.waypointIds[0] });
} else {
this.track(undefined);
2025-10-18 16:10:08 +02:00
}
2025-10-05 19:34:05 +02:00
}
reset() {
2026-10-04 17:09:41 +02:00
this._explicit = undefined;
this.track(undefined);
2025-10-05 19:34:05 +02:00
}
2026-10-04 17:09:41 +02:00
get waypoint(): WaypointDetails | undefined {
return get(this._selection)?.waypoint;
2025-10-05 19:34:05 +02:00
}
get fileId(): string | undefined {
2026-10-04 17:09:41 +02:00
return get(this._selection)?.fileId;
}
get id(): string | undefined {
return get(this._selection)?.id;
}
private track(target: { fileId: string; id: string } | undefined) {
this._fileUnsubscribe?.();
this._fileUnsubscribe = undefined;
if (!target) {
this._selection.set(undefined);
return;
}
// read again each time the file changes
const read = () => {
const waypoint = engine.waypoint(target.fileId, target.id);
this._selection.set(waypoint ? { ...target, waypoint } : undefined);
};
const file = get(engine.files).get(target.fileId);
if (file) {
this._fileUnsubscribe = file.subscribe(read);
} else {
read();
}
2025-10-05 19:34:05 +02:00
}
}
export const selectedWaypoint = new WaypointSelection();