Go to frame in clip

This commit is contained in:
Skyler Lehmkuhl 2024-12-18 19:01:50 -05:00
parent d9a06e417a
commit c7c2cd3744
1 changed files with 142 additions and 14 deletions

View File

@ -76,7 +76,51 @@ let clipboard = []
let tools = { let tools = {
select: { select: {
icon: "/assets/select.svg", 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 "<multiple>"
}
},
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: { transform: {
@ -842,6 +886,7 @@ let actions = {
context.selection.push(group) context.selection.push(group)
} }
updateUI() updateUI()
updateInfopanel()
}, },
rollback: (action) => { rollback: (action) => {
let group = pointerList[action.groupUuid] let group = pointerList[action.groupUuid]
@ -858,6 +903,7 @@ let actions = {
} }
parent.removeChild(group) parent.removeChild(group)
updateUI() updateUI()
updateInfopanel()
} }
}, },
sendToBack: { sendToBack: {
@ -972,6 +1018,29 @@ let actions = {
updateUI() 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() { function uuidv4() {
@ -1805,9 +1874,26 @@ class GraphicsObject {
get maxFrame() { get maxFrame() {
return Math.max(this.layers.map((layer)=>{return layer.frames.length})) 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) { getFrame(num) {
return this.activeLayer.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() { bbox() {
let bbox; let bbox;
for (let layer of this.layers) { for (let layer of this.layers) {
@ -2004,6 +2090,7 @@ class GraphicsObject {
rotation: 0, rotation: 0,
scale_x: 1, scale_x: 1,
scale_y: 1, scale_y: 1,
goToFrame: 1,
} }
} }
removeShape(shape) { removeShape(shape) {
@ -2243,7 +2330,7 @@ function playPause() {
} }
function advanceFrame() { function advanceFrame() {
context.activeObject.currentFrameNum += 1 context.activeObject.advanceFrame()
updateLayers() updateLayers()
updateMenu() updateMenu()
updateUI() updateUI()
@ -2263,12 +2350,10 @@ function advanceFrame() {
} }
function decrementFrame() { function decrementFrame() {
if (context.activeObject.currentFrameNum > 0) { context.activeObject.decrementFrame()
context.activeObject.currentFrameNum -= 1 updateLayers()
updateLayers() updateMenu()
updateMenu() updateUI()
updateUI()
}
} }
function _newFile(width, height, fps) { function _newFile(width, height, fps) {
@ -2911,6 +2996,7 @@ function stage() {
} }
context.lastMouse = mouse context.lastMouse = mouse
updateUI() updateUI()
updateInfopanel()
}) })
stage.addEventListener("mouseup", (e) => { stage.addEventListener("mouseup", (e) => {
context.mouseDown = false context.mouseDown = false
@ -2970,6 +3056,7 @@ function stage() {
context.activeCurve = undefined context.activeCurve = undefined
updateUI() updateUI()
updateMenu() updateMenu()
updateInfopanel()
}) })
stage.addEventListener("mousemove", (e) => { stage.addEventListener("mousemove", (e) => {
let mouse = getMousePos(stage, e) let mouse = getMousePos(stage, e)
@ -3805,7 +3892,7 @@ function updateLayers() {
layerTrack.addEventListener("click", (e) => { layerTrack.addEventListener("click", (e) => {
let mouse = getMousePos(layerTrack, e) let mouse = getMousePos(layerTrack, e)
let frameNum = parseInt(mouse.x/25) let frameNum = parseInt(mouse.x/25)
context.activeObject.currentFrameNum = frameNum context.activeObject.setFrameNum(frameNum)
updateLayers() updateLayers()
updateMenu() updateMenu()
updateUI() updateUI()
@ -3926,7 +4013,12 @@ function updateInfopanel() {
input = document.createElement("input") input = document.createElement("input")
input.className = "infopanel-input" input.className = "infopanel-input"
input.type = "number" 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) { if (prop.min) {
input.min = prop.min input.min = prop.min
} }
@ -3937,6 +4029,7 @@ function updateInfopanel() {
case "enum": case "enum":
input = document.createElement("select") input = document.createElement("select")
input.className = "infopanel-input" input.className = "infopanel-input"
input.disabled = prop.enabled==undefined ? false : !prop.enabled()
let optionEl; let optionEl;
for (let option of prop.options) { for (let option of prop.options) {
optionEl = document.createElement("option") optionEl = document.createElement("option")
@ -3944,20 +4037,43 @@ function updateInfopanel() {
optionEl.innerText = option optionEl.innerText = option
input.appendChild(optionEl) input.appendChild(optionEl)
} }
input.value = getProperty(context, property) if (prop.value) {
input.value = prop.value.get()
} else {
input.value = getProperty(context, property)
}
break; break;
case "boolean": case "boolean":
input = document.createElement("input") input = document.createElement("input")
input.className = "infopanel-input" input.className = "infopanel-input"
input.type = "checkbox" 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; break;
} }
input.addEventListener("input", (e) => { input.addEventListener("input", (e) => {
switch (prop.type) { switch (prop.type) {
case "number": case "number":
if (!isNaN(e.target.value) && e.target.value > 0) { 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; break;
case "enum": case "enum":
@ -3966,7 +4082,19 @@ function updateInfopanel() {
} }
break; break;
case "boolean": 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;
} }
}) })