mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-01 16:22:32 +00:00
hide any file item and undo-redo it
This commit is contained in:
106
gpx/src/gpx.ts
106
gpx/src/gpx.ts
@@ -123,7 +123,7 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
if (gpx) {
|
if (gpx) {
|
||||||
this.attributes = gpx.attributes
|
this.attributes = gpx.attributes
|
||||||
this.metadata = gpx.metadata;
|
this.metadata = gpx.metadata;
|
||||||
this.wpt = gpx.wpt ? gpx.wpt.map((waypoint, index) => new Waypoint(waypoint, index)) : [];
|
this.wpt = gpx.wpt ? gpx.wpt.map((waypoint) => new Waypoint(waypoint)) : [];
|
||||||
this.trk = gpx.trk ? gpx.trk.map((track) => new Track(track)) : [];
|
this.trk = gpx.trk ? gpx.trk.map((track) => new Track(track)) : [];
|
||||||
if (gpx.hasOwnProperty('_data')) {
|
if (gpx.hasOwnProperty('_data')) {
|
||||||
this._data = gpx._data;
|
this._data = gpx._data;
|
||||||
@@ -134,6 +134,17 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
this.wpt = [];
|
this.wpt = [];
|
||||||
this.trk = [new Track()];
|
this.trk = [new Track()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.trk.forEach((track, trackIndex) => {
|
||||||
|
track._data['trackIndex'] = trackIndex;
|
||||||
|
track.trkseg.forEach((segment, segmentIndex) => {
|
||||||
|
segment._data['trackIndex'] = trackIndex;
|
||||||
|
segment._data['segmentIndex'] = segmentIndex;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.wpt.forEach((waypoint, waypointIndex) => {
|
||||||
|
waypoint._data['index'] = waypointIndex;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get children(): ReadonlyArray<Track> {
|
get children(): ReadonlyArray<Track> {
|
||||||
@@ -367,6 +378,63 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHidden(hidden: boolean, trackIndices?: number[], segmentIndices?: number[]) {
|
||||||
|
return produce(this, (draft) => {
|
||||||
|
let og = getOriginal(draft); // Read as much as possible from the original object because it is faster
|
||||||
|
let allHidden = hidden;
|
||||||
|
let trk = og.trk.map((track, index) => {
|
||||||
|
if (trackIndices === undefined || trackIndices.includes(index)) {
|
||||||
|
return track.setHidden(hidden, segmentIndices);
|
||||||
|
} else {
|
||||||
|
allHidden = allHidden && (track._data.hidden === true);
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
draft.trk = freeze(trk); // Pre-freeze the array, faster as well
|
||||||
|
|
||||||
|
let wpt = og.wpt.map((waypoint) => {
|
||||||
|
if (trackIndices === undefined && segmentIndices === undefined) {
|
||||||
|
return waypoint.setHidden(hidden);
|
||||||
|
} else {
|
||||||
|
allHidden = allHidden && (waypoint._data.hidden === true);
|
||||||
|
return waypoint;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
draft.wpt = freeze(wpt); // Pre-freeze the array, faster as well
|
||||||
|
|
||||||
|
if (trackIndices === undefined && segmentIndices === undefined) {
|
||||||
|
draft._data.hiddenWpt = hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
draft._data.hidden = allHidden;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setHiddenWaypoints(hidden: boolean, waypointIndices?: number[]) {
|
||||||
|
return produce(this, (draft) => {
|
||||||
|
let og = getOriginal(draft); // Read as much as possible from the original object because it is faster
|
||||||
|
|
||||||
|
let allHiddenWpt = hidden;
|
||||||
|
let wpt = og.wpt.map((waypoint, index) => {
|
||||||
|
if (waypointIndices === undefined || waypointIndices.includes(index)) {
|
||||||
|
return waypoint.setHidden(hidden);
|
||||||
|
} else {
|
||||||
|
allHiddenWpt = allHiddenWpt && (waypoint._data.hidden === true);
|
||||||
|
return waypoint;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
draft.wpt = freeze(wpt); // Pre-freeze the array, faster as well
|
||||||
|
|
||||||
|
let allHiddenTrk = true;
|
||||||
|
og.trk.forEach((track) => {
|
||||||
|
allHiddenTrk = allHiddenTrk && (track._data.hidden === true);
|
||||||
|
});
|
||||||
|
|
||||||
|
draft._data.hiddenWpt = allHiddenWpt;
|
||||||
|
draft._data.hidden = allHiddenTrk && allHiddenWpt;
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A class that represents a Track in a GPX file
|
// A class that represents a Track in a GPX file
|
||||||
@@ -573,7 +641,24 @@ export class Track extends GPXTreeNode<TrackSegment> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
setHidden(hidden: boolean, segmentIndices?: number[]) {
|
||||||
|
return produce(this, (draft) => {
|
||||||
|
let og = getOriginal(draft); // Read as much as possible from the original object because it is faster
|
||||||
|
let allHidden = hidden;
|
||||||
|
let trkseg = og.trkseg.map((segment, index) => {
|
||||||
|
if (segmentIndices === undefined || segmentIndices.includes(index)) {
|
||||||
|
return segment.setHidden(hidden);
|
||||||
|
} else {
|
||||||
|
allHidden = allHidden && (segment._data.hidden === true);
|
||||||
|
return segment;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
draft.trkseg = freeze(trkseg); // Pre-freeze the array, faster as well
|
||||||
|
draft._data.hidden = allHidden;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A class that represents a TrackSegment in a GPX file
|
// A class that represents a TrackSegment in a GPX file
|
||||||
export class TrackSegment extends GPXTreeLeaf {
|
export class TrackSegment extends GPXTreeLeaf {
|
||||||
@@ -881,6 +966,11 @@ export class TrackSegment extends GPXTreeLeaf {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setHidden(hidden: boolean) {
|
||||||
|
return produce(this, (draft) => {
|
||||||
|
draft._data.hidden = hidden;
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export class TrackPoint {
|
export class TrackPoint {
|
||||||
@@ -985,7 +1075,7 @@ export class Waypoint {
|
|||||||
type?: string;
|
type?: string;
|
||||||
_data: { [key: string]: any } = {};
|
_data: { [key: string]: any } = {};
|
||||||
|
|
||||||
constructor(waypoint: WaypointType & { _data?: any } | Waypoint, index?: number) {
|
constructor(waypoint: WaypointType & { _data?: any } | Waypoint) {
|
||||||
this.attributes = waypoint.attributes;
|
this.attributes = waypoint.attributes;
|
||||||
this.ele = waypoint.ele;
|
this.ele = waypoint.ele;
|
||||||
this.time = waypoint.time;
|
this.time = waypoint.time;
|
||||||
@@ -998,9 +1088,6 @@ export class Waypoint {
|
|||||||
if (waypoint.hasOwnProperty('_data')) {
|
if (waypoint.hasOwnProperty('_data')) {
|
||||||
this._data = waypoint._data;
|
this._data = waypoint._data;
|
||||||
}
|
}
|
||||||
if (index !== undefined) {
|
|
||||||
this._data['index'] = index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCoordinates(): Coordinates {
|
getCoordinates(): Coordinates {
|
||||||
@@ -1032,6 +1119,13 @@ export class Waypoint {
|
|||||||
type: this.type,
|
type: this.type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Producers
|
||||||
|
setHidden(hidden: boolean) {
|
||||||
|
return produce(this, (draft) => {
|
||||||
|
draft._data.hidden = hidden;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GPXStatistics {
|
export class GPXStatistics {
|
||||||
|
@@ -48,11 +48,8 @@
|
|||||||
triggerFileInput,
|
triggerFileInput,
|
||||||
createFile,
|
createFile,
|
||||||
loadFiles,
|
loadFiles,
|
||||||
toggleSelectionVisibility,
|
|
||||||
updateSelectionFromKey,
|
updateSelectionFromKey,
|
||||||
showSelection,
|
allHidden,
|
||||||
hideSelection,
|
|
||||||
anyHidden,
|
|
||||||
editMetadata,
|
editMetadata,
|
||||||
editStyle,
|
editStyle,
|
||||||
exportState,
|
exportState,
|
||||||
@@ -231,15 +228,15 @@
|
|||||||
</Menubar.Item>
|
</Menubar.Item>
|
||||||
<Menubar.Item
|
<Menubar.Item
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if ($anyHidden) {
|
if ($allHidden) {
|
||||||
showSelection();
|
dbUtils.setHiddenToSelection(false);
|
||||||
} else {
|
} else {
|
||||||
hideSelection();
|
dbUtils.setHiddenToSelection(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={$selection.size == 0}
|
disabled={$selection.size == 0}
|
||||||
>
|
>
|
||||||
{#if $anyHidden}
|
{#if $allHidden}
|
||||||
<Eye size="16" class="mr-1" />
|
<Eye size="16" class="mr-1" />
|
||||||
{$_('menu.unhide')}
|
{$_('menu.unhide')}
|
||||||
{:else}
|
{:else}
|
||||||
@@ -249,7 +246,7 @@
|
|||||||
<Shortcut key="H" ctrl={true} />
|
<Shortcut key="H" ctrl={true} />
|
||||||
</Menubar.Item>
|
</Menubar.Item>
|
||||||
<Menubar.Separator />
|
<Menubar.Separator />
|
||||||
<Menubar.Item on:click={selectAll}>
|
<Menubar.Item on:click={selectAll} disabled={$fileObservers.size == 0}>
|
||||||
<FileStack size="16" class="mr-1" />
|
<FileStack size="16" class="mr-1" />
|
||||||
{$_('menu.select_all')}
|
{$_('menu.select_all')}
|
||||||
<Shortcut key="A" ctrl={true} />
|
<Shortcut key="A" ctrl={true} />
|
||||||
@@ -543,7 +540,11 @@
|
|||||||
$verticalFileView = !$verticalFileView;
|
$verticalFileView = !$verticalFileView;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (e.key === 'h' && (e.metaKey || e.ctrlKey)) {
|
} else if (e.key === 'h' && (e.metaKey || e.ctrlKey)) {
|
||||||
toggleSelectionVisibility();
|
if ($allHidden) {
|
||||||
|
dbUtils.setHiddenToSelection(false);
|
||||||
|
} else {
|
||||||
|
dbUtils.setHiddenToSelection(true);
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (e.key === 'F1') {
|
} else if (e.key === 'F1') {
|
||||||
switchBasemaps();
|
switchBasemaps();
|
||||||
|
@@ -5,8 +5,8 @@
|
|||||||
import { fileObservers, settings } from '$lib/db';
|
import { fileObservers, settings } from '$lib/db';
|
||||||
import { setContext } from 'svelte';
|
import { setContext } from 'svelte';
|
||||||
import { ListFileItem, ListLevel, ListRootItem, allowedPastes } from './FileList';
|
import { ListFileItem, ListLevel, ListRootItem, allowedPastes } from './FileList';
|
||||||
import { copied, pasteSelection, selection } from './Selection';
|
import { copied, pasteSelection, selectAll, selection } from './Selection';
|
||||||
import { ClipboardPaste, Plus } from 'lucide-svelte';
|
import { ClipboardPaste, FileStack, Plus } from 'lucide-svelte';
|
||||||
import Shortcut from '$lib/components/Shortcut.svelte';
|
import Shortcut from '$lib/components/Shortcut.svelte';
|
||||||
import { _ } from 'svelte-i18n';
|
import { _ } from 'svelte-i18n';
|
||||||
import { createFile } from '$lib/stores';
|
import { createFile } from '$lib/stores';
|
||||||
@@ -66,6 +66,12 @@
|
|||||||
<Shortcut key="+" ctrl={true} />
|
<Shortcut key="+" ctrl={true} />
|
||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
<ContextMenu.Separator />
|
<ContextMenu.Separator />
|
||||||
|
<ContextMenu.Item on:click={selectAll} disabled={$fileObservers.size === 0}>
|
||||||
|
<FileStack size="16" class="mr-1" />
|
||||||
|
{$_('menu.select_all')}
|
||||||
|
<Shortcut key="A" ctrl={true} />
|
||||||
|
</ContextMenu.Item>
|
||||||
|
<ContextMenu.Separator />
|
||||||
<ContextMenu.Item
|
<ContextMenu.Item
|
||||||
disabled={$copied === undefined ||
|
disabled={$copied === undefined ||
|
||||||
$copied.length === 0 ||
|
$copied.length === 0 ||
|
||||||
|
@@ -14,8 +14,10 @@
|
|||||||
import FileListNodeLabel from './FileListNodeLabel.svelte';
|
import FileListNodeLabel from './FileListNodeLabel.svelte';
|
||||||
import { afterUpdate, getContext } from 'svelte';
|
import { afterUpdate, getContext } from 'svelte';
|
||||||
import {
|
import {
|
||||||
|
ListFileItem,
|
||||||
ListTrackSegmentItem,
|
ListTrackSegmentItem,
|
||||||
ListWaypointItem,
|
ListWaypointItem,
|
||||||
|
ListWaypointsItem,
|
||||||
type ListItem,
|
type ListItem,
|
||||||
type ListTrackItem
|
type ListTrackItem
|
||||||
} from './FileList';
|
} from './FileList';
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
let collapsible: CollapsibleTreeNode;
|
let collapsible: CollapsibleTreeNode;
|
||||||
|
|
||||||
$: label =
|
$: label =
|
||||||
node instanceof GPXFile
|
node instanceof GPXFile && item instanceof ListFileItem
|
||||||
? node.metadata.name
|
? node.metadata.name
|
||||||
: node instanceof Track
|
: node instanceof Track
|
||||||
? node.name ?? `${$_('gpx.track')} ${(item as ListTrackItem).trackIndex + 1}`
|
? node.name ?? `${$_('gpx.track')} ${(item as ListTrackItem).trackIndex + 1}`
|
||||||
@@ -42,7 +44,7 @@
|
|||||||
? `${$_('gpx.segment')} ${(item as ListTrackSegmentItem).segmentIndex + 1}`
|
? `${$_('gpx.segment')} ${(item as ListTrackSegmentItem).segmentIndex + 1}`
|
||||||
: node instanceof Waypoint
|
: node instanceof Waypoint
|
||||||
? node.name ?? `${$_('gpx.waypoint')} ${(item as ListWaypointItem).waypointIndex + 1}`
|
? node.name ?? `${$_('gpx.waypoint')} ${(item as ListWaypointItem).waypointIndex + 1}`
|
||||||
: Array.isArray(node) && node.length > 0 && node[0] instanceof Waypoint
|
: node instanceof GPXFile && item instanceof ListWaypointsItem
|
||||||
? $_('gpx.waypoints')
|
? $_('gpx.waypoints')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
@@ -12,14 +12,21 @@
|
|||||||
import { get, writable, type Readable, type Writable } from 'svelte/store';
|
import { get, writable, type Readable, type Writable } from 'svelte/store';
|
||||||
import FileListNodeStore from './FileListNodeStore.svelte';
|
import FileListNodeStore from './FileListNodeStore.svelte';
|
||||||
import FileListNode from './FileListNode.svelte';
|
import FileListNode from './FileListNode.svelte';
|
||||||
import { ListLevel, ListRootItem, allowedMoves, moveItems, type ListItem } from './FileList';
|
import {
|
||||||
|
ListFileItem,
|
||||||
|
ListLevel,
|
||||||
|
ListRootItem,
|
||||||
|
ListWaypointsItem,
|
||||||
|
allowedMoves,
|
||||||
|
moveItems,
|
||||||
|
type ListItem
|
||||||
|
} from './FileList';
|
||||||
import { selection } from './Selection';
|
import { selection } from './Selection';
|
||||||
import { _ } from 'svelte-i18n';
|
import { _ } from 'svelte-i18n';
|
||||||
|
|
||||||
export let node:
|
export let node:
|
||||||
| Map<string, Readable<GPXFileWithStatistics | undefined>>
|
| Map<string, Readable<GPXFileWithStatistics | undefined>>
|
||||||
| GPXTreeElement<AnyGPXTreeElement>
|
| GPXTreeElement<AnyGPXTreeElement>
|
||||||
| ReadonlyArray<Readonly<Waypoint>>
|
|
||||||
| Readonly<Waypoint>;
|
| Readonly<Waypoint>;
|
||||||
export let item: ListItem;
|
export let item: ListItem;
|
||||||
export let waypointRoot: boolean = false;
|
export let waypointRoot: boolean = false;
|
||||||
@@ -32,7 +39,9 @@
|
|||||||
: node instanceof GPXFile
|
: node instanceof GPXFile
|
||||||
? waypointRoot
|
? waypointRoot
|
||||||
? ListLevel.WAYPOINTS
|
? ListLevel.WAYPOINTS
|
||||||
: ListLevel.TRACK
|
: item instanceof ListWaypointsItem
|
||||||
|
? ListLevel.WAYPOINT
|
||||||
|
: ListLevel.TRACK
|
||||||
: node instanceof Track
|
: node instanceof Track
|
||||||
? ListLevel.SEGMENT
|
? ListLevel.SEGMENT
|
||||||
: ListLevel.WAYPOINT;
|
: ListLevel.WAYPOINT;
|
||||||
@@ -268,10 +277,16 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if node instanceof GPXFile}
|
{:else if node instanceof GPXFile}
|
||||||
{#if waypointRoot}
|
{#if item instanceof ListWaypointsItem}
|
||||||
|
{#each node.wpt as wpt, i (wpt)}
|
||||||
|
<div data-id={i} class="ml-1">
|
||||||
|
<FileListNode node={wpt} item={item.extend(i)} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{:else if waypointRoot}
|
||||||
{#if node.wpt.length > 0}
|
{#if node.wpt.length > 0}
|
||||||
<div data-id="waypoints">
|
<div data-id="waypoints">
|
||||||
<FileListNode node={node.wpt} item={item.extend('waypoints')} />
|
<FileListNode {node} item={item.extend('waypoints')} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
@@ -287,16 +302,10 @@
|
|||||||
<FileListNode node={child} item={item.extend(i)} />
|
<FileListNode node={child} item={item.extend(i)} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if Array.isArray(node) && node.length > 0 && node[0] instanceof Waypoint}
|
|
||||||
{#each node as wpt, i (wpt)}
|
|
||||||
<div data-id={i} class="ml-1">
|
|
||||||
<FileListNode node={wpt} item={item.extend(i)} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if node instanceof GPXFile}
|
{#if node instanceof GPXFile && item instanceof ListFileItem}
|
||||||
{#if !waypointRoot}
|
{#if !waypointRoot}
|
||||||
<svelte:self {node} {item} waypointRoot={true} />
|
<svelte:self {node} {item} waypointRoot={true} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -38,15 +38,7 @@
|
|||||||
} from './Selection';
|
} from './Selection';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import {
|
import { allHidden, editMetadata, editStyle, gpxLayers, map } from '$lib/stores';
|
||||||
anyHidden,
|
|
||||||
editMetadata,
|
|
||||||
editStyle,
|
|
||||||
gpxLayers,
|
|
||||||
hideSelection,
|
|
||||||
map,
|
|
||||||
showSelection
|
|
||||||
} from '$lib/stores';
|
|
||||||
import {
|
import {
|
||||||
GPXTreeElement,
|
GPXTreeElement,
|
||||||
Track,
|
Track,
|
||||||
@@ -189,9 +181,18 @@
|
|||||||
{:else if item.level === ListLevel.WAYPOINT}
|
{:else if item.level === ListLevel.WAYPOINT}
|
||||||
<MapPin size="16" class="mr-1 shrink-0" />
|
<MapPin size="16" class="mr-1 shrink-0" />
|
||||||
{/if}
|
{/if}
|
||||||
<span class="grow select-none truncate {$verticalFileView ? 'mr-2' : ''}">
|
<span class="grow select-none truncate {$verticalFileView ? 'last:mr-2' : ''}">
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
|
{#if (item.level !== ListLevel.WAYPOINTS && node._data.hidden) || (item.level === ListLevel.WAYPOINTS && node._data.hiddenWpt)}
|
||||||
|
<EyeOff
|
||||||
|
size="12"
|
||||||
|
class="shrink-0 mt-1 ml-1 {$verticalFileView ? 'mr-2' : ''} {item.level ===
|
||||||
|
ListLevel.SEGMENT || item.level === ListLevel.WAYPOINT
|
||||||
|
? 'mr-3'
|
||||||
|
: ''}"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</ContextMenu.Trigger>
|
</ContextMenu.Trigger>
|
||||||
@@ -206,28 +207,26 @@
|
|||||||
<PaintBucket size="16" class="mr-1" />
|
<PaintBucket size="16" class="mr-1" />
|
||||||
{$_('menu.style.button')}
|
{$_('menu.style.button')}
|
||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
{#if item instanceof ListFileItem}
|
|
||||||
<ContextMenu.Item
|
|
||||||
on:click={() => {
|
|
||||||
if ($anyHidden) {
|
|
||||||
showSelection();
|
|
||||||
} else {
|
|
||||||
hideSelection();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#if $anyHidden}
|
|
||||||
<Eye size="16" class="mr-1" />
|
|
||||||
{$_('menu.unhide')}
|
|
||||||
{:else}
|
|
||||||
<EyeOff size="16" class="mr-1" />
|
|
||||||
{$_('menu.hide')}
|
|
||||||
{/if}
|
|
||||||
<Shortcut key="H" ctrl={true} />
|
|
||||||
</ContextMenu.Item>
|
|
||||||
{/if}
|
|
||||||
<ContextMenu.Separator />
|
|
||||||
{/if}
|
{/if}
|
||||||
|
<ContextMenu.Item
|
||||||
|
on:click={() => {
|
||||||
|
if ($allHidden) {
|
||||||
|
dbUtils.setHiddenToSelection(false);
|
||||||
|
} else {
|
||||||
|
dbUtils.setHiddenToSelection(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#if $allHidden}
|
||||||
|
<Eye size="16" class="mr-1" />
|
||||||
|
{$_('menu.unhide')}
|
||||||
|
{:else}
|
||||||
|
<EyeOff size="16" class="mr-1" />
|
||||||
|
{$_('menu.hide')}
|
||||||
|
{/if}
|
||||||
|
<Shortcut key="H" ctrl={true} />
|
||||||
|
</ContextMenu.Item>
|
||||||
|
<ContextMenu.Separator />
|
||||||
{#if $verticalFileView}
|
{#if $verticalFileView}
|
||||||
{#if item instanceof ListFileItem}
|
{#if item instanceof ListFileItem}
|
||||||
<ContextMenu.Item
|
<ContextMenu.Item
|
||||||
|
@@ -50,7 +50,6 @@ export class GPXLayer {
|
|||||||
fileId: string;
|
fileId: string;
|
||||||
file: Readable<GPXFileWithStatistics | undefined>;
|
file: Readable<GPXFileWithStatistics | undefined>;
|
||||||
layerColor: string;
|
layerColor: string;
|
||||||
hidden: boolean = false;
|
|
||||||
markers: mapboxgl.Marker[] = [];
|
markers: mapboxgl.Marker[] = [];
|
||||||
selected: boolean = false;
|
selected: boolean = false;
|
||||||
draggable: boolean;
|
draggable: boolean;
|
||||||
@@ -165,6 +164,15 @@ export class GPXLayer {
|
|||||||
this.map.removeLayer(this.fileId + '-direction');
|
this.map.removeLayer(this.fileId + '-direction');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let visibleItems: [number, number][] = [];
|
||||||
|
file.forEachSegment((segment, trackIndex, segmentIndex) => {
|
||||||
|
if (!segment._data.hidden) {
|
||||||
|
visibleItems.push([trackIndex, segmentIndex]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.map.setFilter(this.fileId, ['any', ...visibleItems.map(([trackIndex, segmentIndex]) => ['all', ['==', 'trackIndex', trackIndex], ['==', 'segmentIndex', segmentIndex]])], { validate: false });
|
||||||
} catch (e) { // No reliable way to check if the map is ready to add sources and layers
|
} catch (e) { // No reliable way to check if the map is ready to add sources and layers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -244,7 +252,11 @@ export class GPXLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.markers.forEach((marker) => {
|
this.markers.forEach((marker) => {
|
||||||
marker.addTo(this.map);
|
if (!marker._waypoint._data.hidden) {
|
||||||
|
marker.addTo(this.map);
|
||||||
|
} else {
|
||||||
|
marker.remove();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,17 +378,6 @@ export class GPXLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleVisibility() {
|
|
||||||
this.hidden = !this.hidden;
|
|
||||||
if (this.hidden) {
|
|
||||||
this.map.setLayoutProperty(this.fileId, 'visibility', 'none');
|
|
||||||
this.markers.forEach(marker => marker.remove());
|
|
||||||
} else {
|
|
||||||
this.map.setLayoutProperty(this.fileId, 'visibility', 'visible');
|
|
||||||
this.markers.forEach(marker => marker.addTo(this.map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getGeoJSON(): GeoJSON.FeatureCollection {
|
getGeoJSON(): GeoJSON.FeatureCollection {
|
||||||
let file = get(this.file)?.file;
|
let file = get(this.file)?.file;
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
@@ -2,7 +2,7 @@ import Dexie, { liveQuery } from 'dexie';
|
|||||||
import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension } from 'gpx';
|
import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension } from 'gpx';
|
||||||
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, castDraft, freeze, produceWithPatches, original, produce } from 'immer';
|
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, castDraft, freeze, produceWithPatches, original, produce } from 'immer';
|
||||||
import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
|
import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
|
||||||
import { gpxStatistics, initTargetMapBounds, splitAs, updateTargetMapBounds } from './stores';
|
import { gpxStatistics, initTargetMapBounds, splitAs, updateAllHidden, updateTargetMapBounds } from './stores';
|
||||||
import { mode } from 'mode-watcher';
|
import { mode } from 'mode-watcher';
|
||||||
import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays, type CustomLayer, defaultOpacities } from './assets/layers';
|
import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays, type CustomLayer, defaultOpacities } from './assets/layers';
|
||||||
import { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection';
|
import { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection';
|
||||||
@@ -192,6 +192,10 @@ function dexieGPXFileStore(id: string): Readable<GPXFileWithStatistics> & { dest
|
|||||||
file: gpx,
|
file: gpx,
|
||||||
statistics
|
statistics
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (get(selection).hasAnyChildren(new ListFileItem(id))) {
|
||||||
|
updateAllHidden();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@@ -203,10 +207,61 @@ function dexieGPXFileStore(id: string): Readable<GPXFileWithStatistics> & { dest
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSelection(updatedFiles: GPXFile[], deletedFileIds: string[]) {
|
||||||
|
let removedItems: ListItem[] = [];
|
||||||
|
|
||||||
|
applyToOrderedItemsFromFile(get(selection).getSelected(), (fileId, level, items) => {
|
||||||
|
let file = updatedFiles.find((file) => file._data.id === fileId);
|
||||||
|
if (file) {
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (item instanceof ListTrackItem) {
|
||||||
|
let newTrackIndex = file.trk.findIndex((track) => track._data.trackIndex === item.getTrackIndex());
|
||||||
|
if (newTrackIndex === -1) {
|
||||||
|
removedItems.push(item);
|
||||||
|
}
|
||||||
|
} else if (item instanceof ListTrackSegmentItem) {
|
||||||
|
let newTrackIndex = file.trk.findIndex((track) => track._data.trackIndex === item.getTrackIndex());
|
||||||
|
if (newTrackIndex === -1) {
|
||||||
|
removedItems.push(item);
|
||||||
|
} else {
|
||||||
|
let newSegmentIndex = file.trk[newTrackIndex].trkseg.findIndex((segment) => segment._data.segmentIndex === item.getSegmentIndex());
|
||||||
|
if (newSegmentIndex === -1) {
|
||||||
|
removedItems.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item instanceof ListWaypointItem) {
|
||||||
|
let newWaypointIndex = file.wpt.findIndex((wpt) => wpt._data.index === item.getWaypointIndex());
|
||||||
|
if (newWaypointIndex === -1) {
|
||||||
|
removedItems.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (deletedFileIds.includes(fileId)) {
|
||||||
|
items.forEach((item) => {
|
||||||
|
removedItems.push(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (removedItems.length > 0) {
|
||||||
|
selection.update(($selection) => {
|
||||||
|
removedItems.forEach((item) => {
|
||||||
|
if (item instanceof ListFileItem) {
|
||||||
|
$selection.deleteChild(item.getFileId());
|
||||||
|
} else {
|
||||||
|
$selection.set(item, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $selection;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Commit the changes to the file state to the database
|
// Commit the changes to the file state to the database
|
||||||
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
||||||
let changedFileIds = getChangedFileIds(patch);
|
let changedFileIds = getChangedFileIds(patch);
|
||||||
let updatedFileIds: string[] = [], deletedFileIds: string[] = [];
|
let updatedFileIds: string[] = [], deletedFileIds: string[] = [];
|
||||||
|
|
||||||
changedFileIds.forEach(id => {
|
changedFileIds.forEach(id => {
|
||||||
if (newFileState.has(id)) {
|
if (newFileState.has(id)) {
|
||||||
updatedFileIds.push(id);
|
updatedFileIds.push(id);
|
||||||
@@ -218,6 +273,8 @@ function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch
|
|||||||
let updatedFiles = updatedFileIds.map(id => newFileState.get(id)).filter(file => file !== undefined) as GPXFile[];
|
let updatedFiles = updatedFileIds.map(id => newFileState.get(id)).filter(file => file !== undefined) as GPXFile[];
|
||||||
updatedFileIds = updatedFiles.map(file => file._data.id);
|
updatedFileIds = updatedFiles.map(file => file._data.id);
|
||||||
|
|
||||||
|
updateSelection(updatedFiles, deletedFileIds);
|
||||||
|
|
||||||
return db.transaction('rw', db.fileids, db.files, async () => {
|
return db.transaction('rw', db.fileids, db.files, async () => {
|
||||||
if (updatedFileIds.length > 0) {
|
if (updatedFileIds.length > 0) {
|
||||||
await db.fileids.bulkPut(updatedFileIds, updatedFileIds);
|
await db.fileids.bulkPut(updatedFileIds, updatedFileIds);
|
||||||
@@ -255,14 +312,6 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
|
|||||||
});
|
});
|
||||||
return $files;
|
return $files;
|
||||||
});
|
});
|
||||||
if (deletedFiles.length > 0) {
|
|
||||||
selection.update(($selection) => {
|
|
||||||
deletedFiles.forEach((fileId) => {
|
|
||||||
$selection.deleteChild(fileId);
|
|
||||||
});
|
|
||||||
return $selection;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
settings.fileOrder.update((order) => {
|
settings.fileOrder.update((order) => {
|
||||||
newFiles.forEach((fileId) => {
|
newFiles.forEach((fileId) => {
|
||||||
if (!order.includes(fileId)) {
|
if (!order.includes(fileId)) {
|
||||||
@@ -427,7 +476,7 @@ export const dbUtils = {
|
|||||||
let ids = getFileIds(get(settings.fileOrder).length);
|
let ids = getFileIds(get(settings.fileOrder).length);
|
||||||
let index = 0;
|
let index = 0;
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
@@ -467,7 +516,7 @@ export const dbUtils = {
|
|||||||
}
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
@@ -504,7 +553,7 @@ export const dbUtils = {
|
|||||||
wpt: []
|
wpt: []
|
||||||
};
|
};
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
@@ -616,7 +665,7 @@ export const dbUtils = {
|
|||||||
}
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
let length = file.getNumberOfTrackPoints();
|
let length = file.getNumberOfTrackPoints();
|
||||||
@@ -645,7 +694,7 @@ export const dbUtils = {
|
|||||||
extractSelection: () => {
|
extractSelection: () => {
|
||||||
return applyGlobal((draft) => {
|
return applyGlobal((draft) => {
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
if (file.trk.length > 1) {
|
if (file.trk.length > 1) {
|
||||||
@@ -678,7 +727,9 @@ export const dbUtils = {
|
|||||||
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
||||||
let t = track.replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
let t = track.replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
||||||
if (track.name) {
|
if (track.name) {
|
||||||
t.name = `${track.name} (${segmentIndex + 1})`;
|
t = produce(t, (t) => {
|
||||||
|
t.name = `${track.name} (${segmentIndex + 1})`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
@@ -734,7 +785,9 @@ export const dbUtils = {
|
|||||||
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
||||||
let t = track.clone().replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
let t = track.clone().replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
||||||
if (track.name) {
|
if (track.name) {
|
||||||
t.name = `${track.name} (${segmentIndex + 1})`;
|
t = produce(t, (t) => {
|
||||||
|
t.name = `${track.name} (${segmentIndex + 1})`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
@@ -749,7 +802,7 @@ export const dbUtils = {
|
|||||||
split(fileId: string, trackIndex: number, segmentIndex: number, coordinates: Coordinates) {
|
split(fileId: string, trackIndex: number, segmentIndex: number, coordinates: Coordinates) {
|
||||||
let splitType = get(splitAs);
|
let splitType = get(splitAs);
|
||||||
return applyGlobal((draft) => {
|
return applyGlobal((draft) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let segment = file.trk[trackIndex].trkseg[segmentIndex];
|
let segment = file.trk[trackIndex].trkseg[segmentIndex];
|
||||||
|
|
||||||
@@ -794,7 +847,7 @@ export const dbUtils = {
|
|||||||
}
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
@@ -824,7 +877,7 @@ export const dbUtils = {
|
|||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
let allItems = Array.from(itemsAndPoints.keys());
|
let allItems = Array.from(itemsAndPoints.keys());
|
||||||
applyToOrderedItemsFromFile(allItems, (fileId, level, items) => {
|
applyToOrderedItemsFromFile(allItems, (fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
@@ -848,7 +901,7 @@ export const dbUtils = {
|
|||||||
}
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file && (level === ListLevel.FILE || level === ListLevel.TRACK)) {
|
if (file && (level === ListLevel.FILE || level === ListLevel.TRACK)) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
@@ -867,6 +920,35 @@ export const dbUtils = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setHiddenToSelection: (hidden: boolean) => {
|
||||||
|
if (get(selection).size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applyGlobal((draft) => {
|
||||||
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
|
let file = getFile(fileId);
|
||||||
|
if (file) {
|
||||||
|
let newFile = file;
|
||||||
|
if (level === ListLevel.FILE) {
|
||||||
|
newFile = file.setHidden(hidden);
|
||||||
|
} else if (level === ListLevel.TRACK) {
|
||||||
|
let trackIndices = items.map((item) => (item as ListTrackItem).getTrackIndex());
|
||||||
|
newFile = newFile.setHidden(hidden, trackIndices);
|
||||||
|
} else if (level === ListLevel.SEGMENT) {
|
||||||
|
let trackIndices = [(items[0] as ListTrackSegmentItem).getTrackIndex()];
|
||||||
|
let segmentIndices = items.map((item) => (item as ListTrackSegmentItem).getSegmentIndex());
|
||||||
|
newFile = newFile.setHidden(hidden, trackIndices, segmentIndices);
|
||||||
|
} else if (level === ListLevel.WAYPOINTS) {
|
||||||
|
newFile = newFile.setHiddenWaypoints(hidden);
|
||||||
|
} else if (level === ListLevel.WAYPOINT) {
|
||||||
|
let waypointIndices = items.map((item) => (item as ListWaypointItem).getWaypointIndex());
|
||||||
|
newFile = newFile.setHiddenWaypoints(hidden, waypointIndices);
|
||||||
|
}
|
||||||
|
draft.set(newFile._data.id, freeze(newFile));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
deleteSelection: () => {
|
deleteSelection: () => {
|
||||||
if (get(selection).size === 0) {
|
if (get(selection).size === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -876,7 +958,7 @@ export const dbUtils = {
|
|||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
draft.delete(fileId);
|
draft.delete(fileId);
|
||||||
} else {
|
} else {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = getFile(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === ListLevel.TRACK) {
|
if (level === ListLevel.TRACK) {
|
||||||
|
@@ -344,56 +344,35 @@ export function exportFile(file: GPXFile) {
|
|||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const anyHidden = writable(false);
|
export const allHidden = writable(false);
|
||||||
function updateAnyHidden() {
|
|
||||||
anyHidden.set(get(selection).getSelected().some((item) => {
|
|
||||||
let layer = gpxLayers.get(item.getFileId());
|
|
||||||
return layer && layer.hidden;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
selection.subscribe(updateAnyHidden);
|
|
||||||
|
|
||||||
export function toggleSelectionVisibility() {
|
export function updateAllHidden() {
|
||||||
let files = new Set<string>();
|
let hidden = true;
|
||||||
get(selection).forEach((item) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
files.add(item.getFileId());
|
let file = getFile(fileId);
|
||||||
});
|
if (file) {
|
||||||
files.forEach((fileId) => {
|
for (let item of items) {
|
||||||
let layer = gpxLayers.get(fileId);
|
if (!hidden) {
|
||||||
if (layer) {
|
return;
|
||||||
layer.toggleVisibility();
|
}
|
||||||
|
|
||||||
|
if (item instanceof ListFileItem) {
|
||||||
|
hidden = hidden && (file._data.hidden === true);
|
||||||
|
} else if (item instanceof ListTrackItem && item.getTrackIndex() < file.trk.length) {
|
||||||
|
hidden = hidden && (file.trk[item.getTrackIndex()]._data.hidden === true);
|
||||||
|
} else if (item instanceof ListTrackSegmentItem && item.getTrackIndex() < file.trk.length && item.getSegmentIndex() < file.trk[item.getTrackIndex()].trkseg.length) {
|
||||||
|
hidden = hidden && (file.trk[item.getTrackIndex()].trkseg[item.getSegmentIndex()]._data.hidden === true);
|
||||||
|
} else if (item instanceof ListWaypointsItem) {
|
||||||
|
hidden = hidden && (file._data.hiddenWpt === true);
|
||||||
|
} else if (item instanceof ListWaypointItem && item.getWaypointIndex() < file.wpt.length) {
|
||||||
|
hidden = hidden && (file.wpt[item.getWaypointIndex()]._data.hidden === true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateAnyHidden();
|
allHidden.set(hidden);
|
||||||
}
|
|
||||||
|
|
||||||
export function hideSelection() {
|
|
||||||
let files = new Set<string>();
|
|
||||||
get(selection).forEach((item) => {
|
|
||||||
files.add(item.getFileId());
|
|
||||||
});
|
|
||||||
files.forEach((fileId) => {
|
|
||||||
let layer = gpxLayers.get(fileId);
|
|
||||||
if (layer && !layer.hidden) {
|
|
||||||
layer.toggleVisibility();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
anyHidden.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showSelection() {
|
|
||||||
let files = new Set<string>();
|
|
||||||
get(selection).forEach((item) => {
|
|
||||||
files.add(item.getFileId());
|
|
||||||
});
|
|
||||||
files.forEach((fileId) => {
|
|
||||||
let layer = gpxLayers.get(fileId);
|
|
||||||
if (layer && layer.hidden) {
|
|
||||||
layer.toggleVisibility();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
anyHidden.set(false);
|
|
||||||
}
|
}
|
||||||
|
selection.subscribe(updateAllHidden);
|
||||||
|
|
||||||
export const editMetadata = writable(false);
|
export const editMetadata = writable(false);
|
||||||
export const editStyle = writable(false);
|
export const editStyle = writable(false);
|
||||||
|
Reference in New Issue
Block a user