Add markers: placement, labels and click-to-pick jump targets
Markers are stored per (page, slot), parallel to the discard flags, so adding or removing a cut keeps them aligned with their slices. On a split they stay with the upper half: a marker sits on a printed symbol and nothing can say which side that symbol landed on, so predictable beats clever. Jump targets are chosen by clicking the slice rather than from the thumbnail strip the plan called for. Less code, and it reads the score instead of a list of thumbnails - which is what you want when hunting for the Coda sign. Any page; PageUp/PageDown while picking. Export resolves (page, slot) to the bundle's array index, the only cross-reference the format has. A jump whose target was discarded or re-cut away is dropped rather than exported dangling, since noteman would have nothing to resolve it to. tests/test_markers.py covers the enum size - that is the coupling between two repos - along with cut-edit alignment, index resolution, the dangling-target drop, and round-trips through both the project file and a real bundle. Closes #28 Closes #29 Closes #30
This commit is contained in:
@@ -39,7 +39,35 @@ def song_json(project: Project, files: list[str]) -> dict:
|
||||
value = project.metadata.get(field)
|
||||
if value:
|
||||
payload[field] = value
|
||||
payload["slices"] = [{"file": name} for name in files]
|
||||
|
||||
kept = project.kept_slices()
|
||||
# Markers reference slices by (page, slot) while editing, because that is
|
||||
# what survives adding and removing cuts. In the bundle they become the
|
||||
# array index, which is the only cross-reference the format has.
|
||||
index_of = {position: i for i, position in enumerate(kept)}
|
||||
|
||||
slices: list[dict] = []
|
||||
for name, (page, slot) in zip(files, kept):
|
||||
entry: dict = {"file": name}
|
||||
markers = []
|
||||
for marker in project.pages[page].markers[slot]:
|
||||
item: dict = {"type": marker.type}
|
||||
if marker.label:
|
||||
item["label"] = marker.label
|
||||
if marker.destination is not None:
|
||||
target = index_of.get(tuple(marker.destination))
|
||||
# A jump whose target was discarded or re-cut away is dropped
|
||||
# rather than exported dangling: noteman would have nothing to
|
||||
# resolve it to.
|
||||
if target is None:
|
||||
continue
|
||||
item["destination"] = target
|
||||
markers.append(item)
|
||||
if markers:
|
||||
entry["markers"] = markers
|
||||
slices.append(entry)
|
||||
|
||||
payload["slices"] = slices
|
||||
return payload
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user