Fix subvariation display, progress bar, and linked-instrument discard

- ast-parser: read for_value= prop for sub-variations (was always null,
  causing fallback to positional "subvariation N" label)
- StatusPoller: calculate progress from currently_rendered_notes /
  notes_in_total; show remaining_time string from status.json
- ShapeEditor/EnvelopeEditor: pass { undo } through onChange so callers
  can revert in-place mutations
- PaneFO: makeChangeHandler stashes undo from info arg; discardEdit
  calls undo() before clearing pendingEdit; depends_on handler provides
  its own undo for the inline node.dependsOn mutation
This commit is contained in:
c0dev0id
2026-06-23 21:28:53 +02:00
parent 2060f109b6
commit 4c392927cf
5 changed files with 48 additions and 50 deletions

View File

@@ -1,7 +1,8 @@
import { h } from 'vue';
// Renders a shape's coord table with cascade-shift and an SVG preview.
// `shape` is mutated in place; `onChange` called after each mutation.
// `shape` is mutated in place; `onChange` called after each mutation with
// { undo } so callers can revert if needed.
export const ShapeEditor = {
props: ['shape', 'onChange'],
@@ -14,27 +15,31 @@ export const ShapeEditor = {
const delta = num - old;
coord[field] = num;
// cascade-shift: if x increased past next coord, shift all following
const shifted = [];
if (field === 'x' && delta > 0) {
for (let j = i + 1; j < props.shape.coords.length; j++) {
if (props.shape.coords[j].x <= num) {
shifted.push({ j, ox: props.shape.coords[j].x });
props.shape.coords[j].x += delta;
} else break;
}
}
props.onChange?.();
props.onChange?.({ undo: () => {
coord[field] = old;
for (const { j, ox } of shifted) props.shape.coords[j].x = ox;
}});
}
function addCoord() {
const coords = props.shape.coords;
const lastX = coords.length ? coords[coords.length - 1].x + 1 : 1;
coords.push({ x: lastX, y: 0, z: 1, isSharp: false });
props.onChange?.();
props.onChange?.({ undo: () => coords.pop() });
}
function removeCoord(i) {
props.shape.coords.splice(i, 1);
props.onChange?.();
const removed = props.shape.coords.splice(i, 1)[0];
props.onChange?.({ undo: () => props.shape.coords.splice(i, 0, removed) });
}
function renderSvg() {
@@ -55,19 +60,14 @@ export const ShapeEditor = {
return [sx, sy];
};
const points = coords.map(c => toSvg(c).join(',') ).join(' ');
const points = coords.map(c => toSvg(c).join(',')).join(' ');
return h('svg', {
class: 'se-shape-svg',
viewBox: `0 0 ${W} ${H}`,
preserveAspectRatio: 'none',
}, [
h('polyline', {
points,
fill: 'none',
stroke: '#2a6aaa',
'stroke-width': '1.5',
}),
h('polyline', { points, fill: 'none', stroke: '#2a6aaa', 'stroke-width': '1.5' }),
...coords.map(c => {
const [sx, sy] = toSvg(c);
return h('circle', { cx: sx, cy: sy, r: 2.5, fill: '#6aacff' });
@@ -101,7 +101,11 @@ export const ShapeEditor = {
})),
h('td', null, h('input', {
type: 'checkbox', checked: !!coord.isSharp,
onChange: e => { coord.isSharp = e.target.checked; props.onChange?.(); },
onChange: e => {
const old = coord.isSharp;
coord.isSharp = e.target.checked;
props.onChange?.({ undo: () => { coord.isSharp = old; } });
},
})),
h('td', null, h('button', { onClick: () => removeCoord(i) }, '✕')),
])