Implement translate duplication
This commit is contained in:
parent
af4e1aedff
commit
93c55899ec
3 changed files with 53 additions and 2 deletions
4
TODO.md
4
TODO.md
|
|
@ -145,8 +145,8 @@ A step-by-step checklist for porting MatterControl's design features to a Vue +
|
||||||
- [x] Left-click object: center/zoom camera on object
|
- [x] Left-click object: center/zoom camera on object
|
||||||
|
|
||||||
### Shift Modifier Behaviors
|
### Shift Modifier Behaviors
|
||||||
- [ ] Click with Shift: add to selection (already in Phase 4)
|
- [x] Click with Shift: add to selection (already in Phase 4)
|
||||||
- [ ] Drag translate handle with Shift: duplicate selection along axis
|
- [x] Drag translate handle with Shift: duplicate selection along axis
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -951,6 +951,27 @@ function onCanvasMouseDown(event: MouseEvent) {
|
||||||
dragState.isRightDrag = event.button === 2 || event.button === 1
|
dragState.isRightDrag = event.button === 2 || event.button === 1
|
||||||
dragState.startMousePosition.copy(mouse)
|
dragState.startMousePosition.copy(mouse)
|
||||||
|
|
||||||
|
// Shift+drag: duplicate selection first, then move duplicates
|
||||||
|
if (isShiftPressed) {
|
||||||
|
const currentSelection = [...sceneStore.selectedObjects]
|
||||||
|
const duplicatedIds: string[] = []
|
||||||
|
|
||||||
|
for (const obj of currentSelection) {
|
||||||
|
const duplicate = sceneStore.duplicateObject(obj.id)
|
||||||
|
if (duplicate) {
|
||||||
|
duplicatedIds.push(duplicate.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the duplicates (originals stay in place)
|
||||||
|
if (duplicatedIds.length > 0) {
|
||||||
|
sceneStore.clearSelection()
|
||||||
|
for (const id of duplicatedIds) {
|
||||||
|
sceneStore.addToSelection(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store original positions and calculate center
|
// Store original positions and calculate center
|
||||||
const selectedMeshes = sceneStore.selectedObjects.map((o) => o.mesh)
|
const selectedMeshes = sceneStore.selectedObjects.map((o) => o.mesh)
|
||||||
if (selectedMeshes.length > 0) {
|
if (selectedMeshes.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,35 @@ export const useSceneStore = defineStore('scene', () => {
|
||||||
selectedIds.value = new Set()
|
selectedIds.value = new Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function duplicateObject(id: string): SceneObject | null {
|
||||||
|
const original = objects.value.find((o) => o.id === id)
|
||||||
|
if (!original || !threeScene) return null
|
||||||
|
|
||||||
|
// Clone the mesh with geometry and material
|
||||||
|
const clonedMesh = original.mesh.clone()
|
||||||
|
clonedMesh.geometry = original.mesh.geometry.clone()
|
||||||
|
if (original.mesh.material instanceof THREE.Material) {
|
||||||
|
clonedMesh.material = original.mesh.material.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new name based on the original
|
||||||
|
const baseName = original.name.replace(/ \d+$/, '') // Remove trailing number if present
|
||||||
|
const objectName = generateName(baseName)
|
||||||
|
|
||||||
|
const sceneObject: SceneObject = {
|
||||||
|
id: generateId(),
|
||||||
|
name: objectName,
|
||||||
|
mesh: clonedMesh,
|
||||||
|
visible: original.visible,
|
||||||
|
locked: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
threeScene.add(clonedMesh)
|
||||||
|
objects.value = [...objects.value, sceneObject]
|
||||||
|
|
||||||
|
return sceneObject
|
||||||
|
}
|
||||||
|
|
||||||
const objectList = computed(() => objects.value)
|
const objectList = computed(() => objects.value)
|
||||||
const objectCount = computed(() => objects.value.length)
|
const objectCount = computed(() => objects.value.length)
|
||||||
const selectedObjects = computed(() => objects.value.filter((o) => selectedIds.value.has(o.id)))
|
const selectedObjects = computed(() => objects.value.filter((o) => selectedIds.value.has(o.id)))
|
||||||
|
|
@ -164,5 +193,6 @@ export const useSceneStore = defineStore('scene', () => {
|
||||||
toggleSelection,
|
toggleSelection,
|
||||||
selectAll,
|
selectAll,
|
||||||
clearSelection,
|
clearSelection,
|
||||||
|
duplicateObject,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue