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:
@@ -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) }, '✕')),
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user