0.18.2: centre crosshair + locked-track selection + eye-on-lock

- Optional centre crosshair: dashed horizontal + vertical lines
  through the effective canvas centre, togglable from the HUD next
  to the crop / mask-preview / stage-preview buttons. Scales with
  zoom and stays visible inside clip-edit.
- Locked clip tracks now behave as if they weren't on the stage —
  the ci-group is listening:false + draggable:false, so selection,
  drag, and transform all pass through. deselectIfLocked also
  clears a clip-instance selection that just got locked out
  (directly or via a parent group).
- Eye toggle stays clickable on locked layer / clip-track rows —
  previous pointer-events:none rule only whitelisted the lock
  button. Hide-in-editor is orthogonal to lock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-24 15:23:13 +02:00
1 parent 5af0cdb3d4
commit 21cf6e9a12
7 files changed
+371 -19

No files matched your search

+40 -15
View File
@@ -1764,6 +1764,10 @@ export const useSceneStore = defineStore('scene', {
if (clipTrack) {
if (locked) clipTrack.locked = true
else delete clipTrack.locked
// Drop a selected instance on this track so the transformer
// doesn't stay latched to a group that no longer accepts
// pointer events.
this.deselectIfLocked()
return
}
const scriptTrack = this.scene.scriptTracks?.find((t) => t.id === trackId)
@@ -1783,27 +1787,48 @@ export const useSceneStore = defineStore('scene', {
* (directly locked or reached by a locked parent group), drop
* the selection so the properties panel, keyboard shortcuts,
* and Konva transformer stop offering edits that would fail
* silently against an ignored click. */
* silently against an ignored click. Also handles the clip-
* instance case — if the selected instance sits on a clip
* track that's now locked (directly or via a parent group),
* the transformer would stay latched to a non-listening group. */
deselectIfLocked() {
const id = this.selectedLayerId
if (!id) return
const sel = this.activeLayers.find((l) => l.id === id)
if (!sel) {
this.selectedLayerId = null
this.selectedLayerIds = []
return
}
if (sel.locked) {
this.selectedLayerId = null
this.selectedLayerIds = []
return
}
for (const g of this.scene.groups ?? []) {
if (g.locked && g.childIds.includes(id)) {
if (id) {
const sel = this.activeLayers.find((l) => l.id === id)
if (!sel) {
this.selectedLayerId = null
this.selectedLayerIds = []
} else if (sel.locked) {
this.selectedLayerId = null
this.selectedLayerIds = []
} else {
for (const g of this.scene.groups ?? []) {
if (g.locked && g.childIds.includes(id)) {
this.selectedLayerId = null
this.selectedLayerIds = []
break
}
}
}
}
const ciId = this.selectedClipInstanceId
if (ciId) {
const inst = this.scene.clipInstances?.find((ci) => ci.id === ciId)
if (!inst) {
this.selectedClipInstanceId = null
return
}
const track = this.scene.clipTracks?.find((t) => t.id === inst.clipTrackId)
if (track?.locked) {
this.selectedClipInstanceId = null
return
}
for (const g of this.scene.groups ?? []) {
if (g.locked && g.childIds.includes(inst.clipTrackId)) {
this.selectedClipInstanceId = null
return
}
}
}
},
setLayerEditorHidden(layerId: string, hidden: boolean) {