1.1.5: settings/media folder details + empty-click deselects everything
- Settings → Media tab now shows per-folder image/audio counts, skipped subfolders, skipped files, and a rescan button. listClipart hard-skips subdirectories and unsupported file extensions, returning a skip report the panel renders. - Empty-click anywhere — chrome, bare stage, empty timeline tracks — clears the full selection (layers, clip instances, keyframes) via a shared useDeselectAll helper. shouldChromeClickDeselect() splits exclusions into interactive elements, overlays, editing panels and timeline selection elements so empty timeline space deselects too.
This commit is contained in:
1 parent
3005d9310d
commit
b0813a1d50
12 files changed
+669
-43
No files matched your search
@@ -37,6 +37,7 @@ import { BUTTON_STATE_TIMES } from '@/types/scene'
|
||||
import { useButtonRuntime } from '@/composables/useButtonRuntime'
|
||||
import { evalAction } from '@/lib/actions'
|
||||
import { t } from '@/i18n'
|
||||
import { useDeselectAll } from '@/composables/useDeselectAll'
|
||||
import { useKfSelection } from '@/composables/useKfSelection'
|
||||
import { showLocked } from '@/composables/useShowLocked'
|
||||
import { expandedTrackOrder } from '@/lib/sceneOrder'
|
||||
@@ -45,6 +46,7 @@ import { CLIP_FALLBACK_BOUNDS, computeClipBounds, type Rect } from '@/lib/clipBo
|
||||
const store = useSceneStore()
|
||||
const clipart = useClipartStore()
|
||||
const { selectedKfs } = useKfSelection()
|
||||
const deselectAll = useDeselectAll()
|
||||
|
||||
const container = ref<HTMLDivElement | null>(null)
|
||||
const containerSize = ref({ width: 0, height: 0 })
|
||||
@@ -2016,7 +2018,7 @@ function finishBoxSelect() {
|
||||
const dPxX = Math.abs(b.curX - b.startX) * zoom.value
|
||||
const dPxY = Math.abs(b.curY - b.startY) * zoom.value
|
||||
if (indices.size === 0 && dPxX < 3 && dPxY < 3) {
|
||||
store.selectLayer(null)
|
||||
deselectAll()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -2030,12 +2032,12 @@ function finishBoxSelect() {
|
||||
const draggedX = Math.abs(b.curX - b.startX) * zoom.value
|
||||
const draggedY = Math.abs(b.curY - b.startY) * zoom.value
|
||||
if (draggedX < 3 && draggedY < 3) {
|
||||
if (!b.additive) store.selectLayer(null)
|
||||
if (!b.additive) deselectAll()
|
||||
return
|
||||
}
|
||||
const stage = stageRef.value?.getStage()
|
||||
if (!stage) {
|
||||
if (!b.additive) store.selectLayer(null)
|
||||
if (!b.additive) deselectAll()
|
||||
return
|
||||
}
|
||||
const hits: string[] = []
|
||||
@@ -2074,7 +2076,7 @@ function finishBoxSelect() {
|
||||
})()
|
||||
: hits
|
||||
if (merged.length === 0) {
|
||||
store.selectLayer(null)
|
||||
deselectAll()
|
||||
return
|
||||
}
|
||||
if (merged.length === 1) {
|
||||
@@ -2615,7 +2617,7 @@ function handleStageMouseDown(e: Konva.KonvaEventObject<MouseEvent>) {
|
||||
if (target.name?.() === 'path-frame-dot') return
|
||||
if (vertexMenu.value) vertexMenu.value = null
|
||||
if (target === target.getStage()) {
|
||||
store.selectLayer(null)
|
||||
deselectAll()
|
||||
return
|
||||
}
|
||||
const id = target.id?.()
|
||||
@@ -2628,11 +2630,20 @@ function handleStageMouseDown(e: Konva.KonvaEventObject<MouseEvent>) {
|
||||
}
|
||||
return
|
||||
}
|
||||
// Bubbled mousedown from a Konva node we don't recognise as a
|
||||
// layer. Use selectLayer(null) — NOT deselectAll — so that any
|
||||
// clip-instance selection just set by an inner @mousedown
|
||||
// handler (e.g. the ci-group's own listener) survives this
|
||||
// bubbled fall-through.
|
||||
store.selectLayer(null)
|
||||
return
|
||||
}
|
||||
const match = store.activeLayers.find((l) => l.id === id)
|
||||
if (!match) {
|
||||
// Same rationale: id-bearing nodes that aren't active layers are
|
||||
// typically ci-group / ci-frame / ci-child shapes whose own
|
||||
// mousedown handler has already run and set the clip-instance
|
||||
// selection. Don't trample that.
|
||||
store.selectLayer(null)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user