123 lines
3.4 KiB
Vue
123 lines
3.4 KiB
Vue
<script setup lang="ts">
|
|
const rect = useSelectionRect();
|
|
const warrenStore = useWarrenStore();
|
|
|
|
const left = computed(() => Math.min(rect.a.x, rect.b.x));
|
|
const top = computed(() => Math.min(rect.a.y, rect.b.y));
|
|
const width = computed(() => Math.abs(rect.a.x - rect.b.x));
|
|
const height = computed(() => Math.abs(rect.a.y - rect.b.y));
|
|
|
|
function onDocumentPointerDown(e: MouseEvent) {
|
|
if (e.button !== 0 || matchMedia('(pointer:coarse)').matches) {
|
|
return;
|
|
}
|
|
|
|
const point = { x: e.x, y: e.y };
|
|
rect.set(
|
|
point,
|
|
point,
|
|
!e.shiftKey ? 'set' : e.ctrlKey ? 'subtract' : 'add'
|
|
);
|
|
}
|
|
|
|
function onDocumentPointerMove(e: MouseEvent) {
|
|
if (!rect.enabled || matchMedia('(pointer:coarse)').matches) {
|
|
return;
|
|
}
|
|
|
|
rect.updateB(e.x, e.y);
|
|
|
|
if (
|
|
rect.mode !== 'set' ||
|
|
warrenStore.selection.size === 0 ||
|
|
!rect.isMinSize()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
warrenStore.clearSelection();
|
|
}
|
|
|
|
function onDocumentPointerUp(e: MouseEvent) {
|
|
if (
|
|
!rect.enabled ||
|
|
e.button !== 0 ||
|
|
matchMedia('(pointer:coarse)').matches
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const left = Math.min(rect.a.x, rect.b.x);
|
|
const top = Math.min(rect.a.y, rect.b.y);
|
|
const width = Math.abs(rect.a.x - rect.b.x);
|
|
const height = Math.abs(rect.a.y - rect.b.y);
|
|
const selectionRect = new DOMRect(left, top, width, height);
|
|
|
|
const isMinSize = rect.isMinSize();
|
|
|
|
rect.disable();
|
|
|
|
if (warrenStore.current == null || warrenStore.current.dir == null) {
|
|
return;
|
|
}
|
|
|
|
if (!isMinSize) {
|
|
warrenStore.clearSelection();
|
|
return;
|
|
}
|
|
|
|
const entryElements = document.querySelectorAll('[data-entry-index]');
|
|
|
|
const targetEntries = [];
|
|
|
|
for (const entry of entryElements) {
|
|
const attributeValue = entry.getAttribute('data-entry-index');
|
|
if (attributeValue == null) {
|
|
continue;
|
|
}
|
|
|
|
const index = parseInt(attributeValue);
|
|
if (isNaN(index)) {
|
|
continue;
|
|
}
|
|
|
|
const entryRect = entry.getBoundingClientRect();
|
|
if (intersectRect(selectionRect, entryRect)) {
|
|
targetEntries.push(warrenStore.current.dir.entries[index]);
|
|
}
|
|
}
|
|
|
|
if (rect.mode === 'set') {
|
|
warrenStore.setSelection(targetEntries);
|
|
} else if (rect.mode === 'add') {
|
|
warrenStore.addMultipleToSelection(targetEntries);
|
|
} else if (rect.mode === 'subtract') {
|
|
warrenStore.removeMultipleFromSelection(targetEntries);
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
document.addEventListener('pointerdown', onDocumentPointerDown);
|
|
document.addEventListener('pointermove', onDocumentPointerMove);
|
|
document.addEventListener('pointerup', onDocumentPointerUp);
|
|
});
|
|
onBeforeUnmount(() => {
|
|
document.removeEventListener('pointerdown', onDocumentPointerDown);
|
|
document.removeEventListener('pointermove', onDocumentPointerMove);
|
|
document.removeEventListener('pointerup', onDocumentPointerUp);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="rect.enabled && rect.isMinSize()"
|
|
:class="[
|
|
'pointer-events-none absolute z-50',
|
|
rect.mode === 'set' && 'bg-primary/20',
|
|
rect.mode === 'add' && 'bg-green-300/20',
|
|
rect.mode === 'subtract' && 'bg-destructive/20',
|
|
]"
|
|
:style="`left: ${left}px; top: ${top}px; width: ${width}px; height: ${height}px;`"
|
|
></div>
|
|
</template>
|