From c7c2cd37443da6c44b7a85a060275000a4158474 Mon Sep 17 00:00:00 2001 From: Skyler Lehmkuhl Date: Wed, 18 Dec 2024 19:01:50 -0500 Subject: [PATCH] Go to frame in clip --- src/main.js | 156 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 142 insertions(+), 14 deletions(-) diff --git a/src/main.js b/src/main.js index 209710b..3657c23 100644 --- a/src/main.js +++ b/src/main.js @@ -76,7 +76,51 @@ let clipboard = [] let tools = { select: { icon: "/assets/select.svg", - properties: {} + properties: { + "selectedObjects": { + type: "text", + label: "Selected Object", + enabled: () => context.selection.length==1, + value: { + get: () => { + if (context.selection.length==1) { + return context.selection[0].name + } else if (context.selection.length==0) { + return "" + } else { + return "" + } + }, + set: (val) => { + if (context.selection.length==1) { + actions.setName.create(context.selection[0], val) + } + } + } + }, + "goToFrame": { + type: "number", + label: "Go To Frame", + enabled: () => context.selection.length==1, + value: { + get: () => { + if (context.selection.length != 1) return undefined + const selectedObject = context.selection[0] + return context.activeObject.currentFrame.keys[selectedObject.idx].goToFrame + }, + set: (val) => { + if (context.selection.length != 1) return undefined + const selectedObject = context.selection[0] + context.activeObject.currentFrame.keys[selectedObject.idx].goToFrame = val + } + } + }, + "play": { + type: "boolean", + label: "Play", + enabled: () => context.selection.length==1 + } + } }, transform: { @@ -842,6 +886,7 @@ let actions = { context.selection.push(group) } updateUI() + updateInfopanel() }, rollback: (action) => { let group = pointerList[action.groupUuid] @@ -858,6 +903,7 @@ let actions = { } parent.removeChild(group) updateUI() + updateInfopanel() } }, sendToBack: { @@ -972,6 +1018,29 @@ let actions = { updateUI() } }, + setName: { + create: (object, name) => { + redoStack.length = 0 + let action = { + object: object.idx, + newName: name, + oldName: object.name + } + undoStack.push({name: 'setName', action: action}) + actions.setName.execute(action) + updateMenu() + }, + execute: (action) => { + let object = pointerList[action.object] + object.name = action.newName + updateInfopanel() + }, + rollback: (action) => { + let object = pointerList[action.object] + object.name = action.oldName + updateInfopanel() + } + }, } function uuidv4() { @@ -1805,9 +1874,26 @@ class GraphicsObject { get maxFrame() { return Math.max(this.layers.map((layer)=>{return layer.frames.length})) } + advanceFrame() { + this.setFrameNum(this.currentFrameNum + 1) + } + decrementFrame() { + this.setFrameNum(this.currentFrameNum - 1) + } getFrame(num) { return this.activeLayer.getFrame(num) } + setFrameNum(num) { + this.currentFrameNum = Math.max(0, Math.min(this.maxFrame, num)) + if (this.currentFrame.frameType=="keyframe") { + for (let child of this.children) { + if (this.currentFrame.keys[child.idx].goToFrame != undefined) { + // Frames are 1-indexed + child.setFrameNum(this.currentFrame.keys[child.idx].goToFrame - 1) + } + } + } + } bbox() { let bbox; for (let layer of this.layers) { @@ -2004,6 +2090,7 @@ class GraphicsObject { rotation: 0, scale_x: 1, scale_y: 1, + goToFrame: 1, } } removeShape(shape) { @@ -2243,7 +2330,7 @@ function playPause() { } function advanceFrame() { - context.activeObject.currentFrameNum += 1 + context.activeObject.advanceFrame() updateLayers() updateMenu() updateUI() @@ -2263,12 +2350,10 @@ function advanceFrame() { } function decrementFrame() { - if (context.activeObject.currentFrameNum > 0) { - context.activeObject.currentFrameNum -= 1 - updateLayers() - updateMenu() - updateUI() - } + context.activeObject.decrementFrame() + updateLayers() + updateMenu() + updateUI() } function _newFile(width, height, fps) { @@ -2911,6 +2996,7 @@ function stage() { } context.lastMouse = mouse updateUI() + updateInfopanel() }) stage.addEventListener("mouseup", (e) => { context.mouseDown = false @@ -2970,6 +3056,7 @@ function stage() { context.activeCurve = undefined updateUI() updateMenu() + updateInfopanel() }) stage.addEventListener("mousemove", (e) => { let mouse = getMousePos(stage, e) @@ -3805,7 +3892,7 @@ function updateLayers() { layerTrack.addEventListener("click", (e) => { let mouse = getMousePos(layerTrack, e) let frameNum = parseInt(mouse.x/25) - context.activeObject.currentFrameNum = frameNum + context.activeObject.setFrameNum(frameNum) updateLayers() updateMenu() updateUI() @@ -3926,7 +4013,12 @@ function updateInfopanel() { input = document.createElement("input") input.className = "infopanel-input" input.type = "number" - input.value = getProperty(context, property) + input.disabled = prop.enabled==undefined ? false : !prop.enabled() + if (prop.value) { + input.value = prop.value.get() + } else { + input.value = getProperty(context, property) + } if (prop.min) { input.min = prop.min } @@ -3937,6 +4029,7 @@ function updateInfopanel() { case "enum": input = document.createElement("select") input.className = "infopanel-input" + input.disabled = prop.enabled==undefined ? false : !prop.enabled() let optionEl; for (let option of prop.options) { optionEl = document.createElement("option") @@ -3944,20 +4037,43 @@ function updateInfopanel() { optionEl.innerText = option input.appendChild(optionEl) } - input.value = getProperty(context, property) + if (prop.value) { + input.value = prop.value.get() + } else { + input.value = getProperty(context, property) + } break; case "boolean": input = document.createElement("input") input.className = "infopanel-input" input.type = "checkbox" - input.checked = getProperty(context, property) + input.disabled = prop.enabled==undefined ? false : !prop.enabled() + if (prop.value) { + input.checked = prop.value.get() + } else { + input.checked = getProperty(context, property) + } + break; + case "text": + input = document.createElement("input") + input.className = "infopanel-input" + input.disabled = prop.enabled==undefined ? false : !prop.enabled() + if (prop.value) { + input.value = prop.value.get() + } else { + input.value = getProperty(context, property) + } break; } input.addEventListener("input", (e) => { switch (prop.type) { case "number": if (!isNaN(e.target.value) && e.target.value > 0) { - setProperty(context, property, parseInt(e.target.value)) + if (prop.value) { + prop.value.set(parseInt(e.target.value)) + } else { + setProperty(context, property, parseInt(e.target.value)) + } } break; case "enum": @@ -3966,7 +4082,19 @@ function updateInfopanel() { } break; case "boolean": - setProperty(context, property, e.target.checked) + if (prop.value) { + prop.value.set(e.target.value) + } else { + setProperty(context, property, e.target.checked) + } + break; + case "text": + if (prop.value) { + prop.value.set(e.target.value) + } else { + setProperty(context, property, parseInt(e.target.value)) + } + break; } })