diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index 33b641b82..e2d37203d 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -1,7 +1,7 @@ -import React, { useCallback, UIEvent } from "react"; +import React, { useCallback } from "react"; import { useMouseEventsTimeline } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsTimeline"; import { - currentScroll, + timelineScrollX, currentTime, dndTimelineHeight, overTimeline, @@ -29,7 +29,7 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => { (event: React.PointerEvent) => { if (event.button === 0) { const newTime = Math.round( - (event.clientX + currentScroll.value - 92) / 4 / scale.value, + (event.clientX + timelineScrollX.value - 92) / 4 / scale.value, ); if (newTime < 0) { return; @@ -45,10 +45,6 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => { [], ); - const onScroll = useCallback((event: UIEvent) => { - currentScroll.value = event.currentTarget.scrollLeft; - }, []); - return ( <> {!onStyle && ( @@ -59,19 +55,13 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => { /> )}
{ overTimeline.value = true; }} onPointerLeave={() => (overTimeline.value = false)} onPointerDown={onTimelineClick} - onScroll={onScroll} > {children}
diff --git a/app/pages/PageEnigma/PageEditor.tsx b/app/pages/PageEnigma/PageEditor.tsx index df2cf03f7..d621f1d16 100644 --- a/app/pages/PageEnigma/PageEditor.tsx +++ b/app/pages/PageEnigma/PageEditor.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from "react"; +import React, { useContext, useRef } from "react"; import { LoadingBar, LoadingDots } from "~/components"; import { SidePanel } from "~/modules/SidePanel"; @@ -33,6 +33,11 @@ export const PageEditor = ({ setPage }: Props) => { useSignals(); const [appUiState] = useContext(AppUiContext); + const r1 = useRef(appUiState); + if (r1.current !== appUiState) { + console.log("app"); + r1.current = appUiState; + } //To prevent the click event from propagating to the canvas: TODO: HANDLE THIS BETTER? const handleOverlayClick = (event: React.MouseEvent) => { @@ -51,6 +56,7 @@ export const PageEditor = ({ setPage }: Props) => { ? pageHeight.value - dndTimelineHeight.value - 68 : pageHeight.value - timelineHeight.value - 68; + console.log("page"); return (
diff --git a/app/pages/PageEnigma/PageEnigmaComponent.tsx b/app/pages/PageEnigma/PageEnigmaComponent.tsx index 4ed8afb80..a849fbdbd 100644 --- a/app/pages/PageEnigma/PageEnigmaComponent.tsx +++ b/app/pages/PageEnigma/PageEnigmaComponent.tsx @@ -20,7 +20,7 @@ export const PageEnigmaComponent = () => { dispatchAppUiState, }); } - }, [editor, dispatchAppUiState]); + }, []); return ( <> diff --git a/app/pages/PageEnigma/PageStyling.tsx b/app/pages/PageEnigma/PageStyling.tsx index d51865076..e2b446674 100644 --- a/app/pages/PageEnigma/PageStyling.tsx +++ b/app/pages/PageEnigma/PageStyling.tsx @@ -1,15 +1,23 @@ import { useSignals } from "@preact/signals-react/runtime"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faAngleLeft } from "@fortawesome/pro-solid-svg-icons"; -import { Button, Link } from "~/components"; +import { Button } from "~/components"; import { StyleSelection } from "~/pages/PageEnigma/comps/StyleSelection"; -import { LowerPanel } from "~/modules/LowerPanel"; -import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid"; +import { TimerGrid } from "~/pages/PageEnigma/comps/Timeline/TimerGrid"; import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber"; import { PreviewImages } from "~/pages/PageEnigma/comps/PreviewImages"; import { TopBar } from "~/modules/TopBar"; -import { useContext } from "react"; +import React, { UIEvent, useCallback, useContext } from "react"; import { EngineContext } from "~/contexts/EngineContext"; +import { + currentTime, + filmLength, + scale, + timelineScrollX, +} from "~/pages/PageEnigma/store"; +import Queue from "~/pages/PageEnigma/Queue/Queue"; +import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; +import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; interface Props { setPage: (page: string) => void; @@ -19,6 +27,8 @@ export const PageStyling = ({ setPage }: Props) => { useSignals(); const editorEngine = useContext(EngineContext); + console.log(timelineScrollX.value); + const generateFrame = async () => { await editorEngine?.generateFrame(); }; @@ -30,7 +40,31 @@ export const PageStyling = ({ setPage }: Props) => { const switchEdit = () => { editorEngine?.switchEdit(); setPage("edit"); - } + }; + + const onScroll = useCallback((event: UIEvent) => { + timelineScrollX.value = event.currentTarget.scrollLeft; + }, []); + + const onTimelineClick = useCallback( + (event: React.PointerEvent) => { + if (event.button === 0) { + const newTime = Math.round( + (event.clientX + timelineScrollX.value - 92) / 4 / scale.value, + ); + if (newTime < 0) { + return; + } + currentTime.value = newTime; + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.UPDATE_TIME, + data: { currentTime: Math.round(newTime) }, + }); + } + }, + [], + ); return (
@@ -50,17 +84,29 @@ export const PageStyling = ({ setPage }: Props) => {
- +
- +
- - - - +
+
+ + +
+
diff --git a/app/pages/PageEnigma/comps/Timeline/Audio.tsx b/app/pages/PageEnigma/comps/Timeline/Audio.tsx index b6d716a76..094aa4fbb 100644 --- a/app/pages/PageEnigma/comps/Timeline/Audio.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Audio.tsx @@ -1,10 +1,5 @@ import { TrackClips } from "~/pages/PageEnigma/comps/Timeline/TrackClips"; -import { - audioGroup, - fullWidth, - toggleAudioMute, - updateAudio, -} from "~/pages/PageEnigma/store"; +import { audioGroup, fullWidth, updateAudio } from "~/pages/PageEnigma/store"; import { ClipGroup } from "~/pages/PageEnigma/models"; export const Audio = () => { @@ -12,21 +7,16 @@ export const Audio = () => { return (
-
- Global Audio -
-
+
diff --git a/app/pages/PageEnigma/comps/Timeline/Camera.tsx b/app/pages/PageEnigma/comps/Timeline/Camera.tsx index 55d97e85d..06a55ad09 100644 --- a/app/pages/PageEnigma/comps/Timeline/Camera.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Camera.tsx @@ -9,11 +9,10 @@ export const Camera = () => { return (
-
Camera
-
+
{ const { updateClipLipSync, updateClipPosition, updateClipAnimations } = useMemo(() => buildUpdaters(updateCharacters), []); - const toggleCharacterLipSyncMute = useCallback(() => { - toggleLipSyncMute(character?.object_uuid ?? ""); - }, [character?.object_uuid]); - - if (!character) { - return false; - } const { animationClips, positionKeyframes, lipSyncClips } = character; return (
-
- Character -
-
+
{ clips={lipSyncClips} title="Lipsync Audio TrackClips" updateClip={updateClipLipSync} - muted={character.muted} - toggleMute={toggleCharacterLipSyncMute} group={ClipGroup.CHARACTER} type={ClipType.AUDIO} /> diff --git a/app/pages/PageEnigma/comps/Timeline/Characters.tsx b/app/pages/PageEnigma/comps/Timeline/Characters.tsx index e95cbfdcb..35b9236b5 100644 --- a/app/pages/PageEnigma/comps/Timeline/Characters.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Characters.tsx @@ -7,7 +7,9 @@ export const Characters = () => { return ( <> {characterGroup.value.characters.map((character) => ( - +
+ +
))} ); diff --git a/app/pages/PageEnigma/comps/Timeline/ObjectGroups.tsx b/app/pages/PageEnigma/comps/Timeline/ObjectGroups.tsx index 3e9e634c5..4dab17818 100644 --- a/app/pages/PageEnigma/comps/Timeline/ObjectGroups.tsx +++ b/app/pages/PageEnigma/comps/Timeline/ObjectGroups.tsx @@ -1,17 +1,17 @@ import { objectGroup } from "~/pages/PageEnigma/store"; import { useSignals } from "@preact/signals-react/runtime"; -import { ObjectTrack } from "~/pages/PageEnigma/comps/Timeline/ObjectTrack"; +import { ObjectTrackComponent } from "~/pages/PageEnigma/comps/Timeline/ObjectTrack"; export const ObjectGroups = () => { useSignals(); return ( <> - {objectGroup.value.objects.length > 0 && ( -
- + {objectGroup.value.objects.map((object) => ( +
+
- )} + ))} ); }; diff --git a/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx b/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx index 6ee246096..da2806c9a 100644 --- a/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx +++ b/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx @@ -1,27 +1,26 @@ -import { fullWidth, objectGroup, updateObject } from "~/pages/PageEnigma/store"; +import { fullWidth, updateObject } from "~/pages/PageEnigma/store"; import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames"; -import { ClipGroup } from "~/pages/PageEnigma/models"; +import { ClipGroup, ObjectTrack } from "~/pages/PageEnigma/models"; -export const ObjectTrack = () => { +interface Props { + object: ObjectTrack; +} + +export const ObjectTrackComponent = ({ object }: Props) => { return (
-
- Objects +
+
- {objectGroup.value.objects.map((object) => ( -
- -
- ))}
); }; diff --git a/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx b/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx new file mode 100644 index 000000000..0d519e7c5 --- /dev/null +++ b/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx @@ -0,0 +1,89 @@ +import { + audioGroup, + characterGroup, + objectGroup, + timelineScrollY, + toggleAudioMute, + toggleLipSyncMute, +} from "~/pages/PageEnigma/store"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faVolume, faVolumeSlash } from "@fortawesome/pro-solid-svg-icons"; +import { useSignals } from "@preact/signals-react/runtime"; + +export const RowHeaders = () => { + useSignals(); + + return ( +
+
+ {characterGroup.value.characters.map((character) => ( +
+
+
+ Character +
+
+ +
+
+
+ ))} +
+
+
+ Camera +
+
+
+
+
+
+ Global Audio +
+
+ +
+
+
+ {objectGroup.value.objects.map((obj) => ( +
+
+
+ Object +
+
+
+ ))} +
+
+ ); +}; diff --git a/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx b/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx index 7f0f24cad..7cea4086b 100644 --- a/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx @@ -1,4 +1,9 @@ -import { currentTime, fullHeight, scale } from "~/pages/PageEnigma/store"; +import { + timelineScrollX, + currentTime, + fullHeight, + scale, +} from "~/pages/PageEnigma/store"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSortDown } from "@fortawesome/pro-solid-svg-icons"; import { useMouseEventsScrubber } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsScrubber"; @@ -9,10 +14,16 @@ export const Scrubber = () => { const { onPointerDown, time } = useMouseEventsScrubber(); const displayTime = time === -1 ? currentTime.value : time; + if (displayTime * 4 * scale.value + 84 - timelineScrollX.value < 84) { + return null; + } return (
diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index dcbc98147..7887b5fe7 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { UIEvent, useCallback, useEffect, useState } from "react"; import { LowerPanel } from "~/modules/LowerPanel"; import { Camera } from "./Camera"; @@ -10,15 +10,21 @@ import { deleteCharacterClip, selectedItem, ignoreDelete, + timelineScrollX, + timelineScrollY, + filmLength, + scale, } from "~/pages/PageEnigma/store"; import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler"; import { useSignals } from "@preact/signals-react/runtime"; -import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid"; +import { TimerGrid } from "~/pages/PageEnigma/comps/Timeline/TimerGrid"; import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber"; import { Characters } from "~/pages/PageEnigma/comps/Timeline/Characters"; import { ObjectGroups } from "~/pages/PageEnigma/comps/Timeline/ObjectGroups"; import useUpdateKeyframe from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateKeyframe"; import { Clip, Keyframe } from "~/pages/PageEnigma/models"; +import { RowHeaders } from "~/pages/PageEnigma/comps/Timeline/RowHeaders"; +import { pageWidth } from "~/store"; function getItemType(item: Clip | Keyframe | null) { if (!item) { @@ -32,6 +38,11 @@ export const Timeline = () => { const [dialogOpen, setDialogOpen] = useState(false); const { deleteKeyframe } = useUpdateKeyframe(); + const onScroll = useCallback((event: UIEvent) => { + timelineScrollX.value = event.currentTarget.scrollLeft; + timelineScrollY.value = event.currentTarget.scrollTop; + }, []); + // implement the code to handle incoming messages from the Engine useQueueHandler(); @@ -75,17 +86,39 @@ export const Timeline = () => { <> -
- +
+
+ +
+
+
+ +
+ +
+
+
+ +
+
+
-
- -
-
-
- - { + useSignals(); + const sectionWidth = 60 * 4 * scale.value; + + return ( +
+
+ {Array(filmLength.value) + .fill(0) + .map((_, index) => ( + +
+ 00:{index < 10 ? "0" + index.toString() : index.toString()} +
+
+ {Array(9) + .fill(0) + .map((_, ind) => ( +
+ ))} + + ))} +
+ 00: + {filmLength.value < 10 + ? "0" + filmLength.value.toString() + : filmLength.value.toString()} +
+
+
+
+ ); +}; diff --git a/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx b/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx index 23952825c..771b152b1 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx @@ -23,8 +23,6 @@ interface Props { title: string; group: ClipGroup; type?: ClipType; - toggleMute?: () => void; - muted?: boolean; updateClip: (options: { id: string; length: number; offset: number }) => void; } @@ -56,9 +54,7 @@ function getCanBuild({ export const TrackClips = ({ id, clips, - toggleMute, updateClip, - muted, title, group, type, @@ -81,7 +77,7 @@ export const TrackClips = ({ return; } - // Now check the the clip fits + // Now check if the clip fits const position = track.getBoundingClientRect(); const clipOffset = (event.clientX - position.x) / 4 / scale.value; @@ -114,49 +110,31 @@ export const TrackClips = ({ } return ( -
-
- {clips.map((clip, index) => ( - 0 ? clips[index - 1].offset + clips[index - 1].length : 0 - } - max={ - index < clips.length - 1 - ? clips[index + 1].offset - : filmLength.value * 60 - } - group={group} - updateClip={updateClip} - clip={clip} - /> - ))} -
- {title} -
- {!!toggleMute && ( - - )} +
+ {clips.map((clip, index) => ( + 0 ? clips[index - 1].offset + clips[index - 1].length : 0 + } + max={ + index < clips.length - 1 + ? clips[index + 1].offset + : filmLength.value * 60 + } + group={group} + updateClip={updateClip} + clip={clip} + /> + ))} +
+ {title}
); diff --git a/app/pages/PageEnigma/comps/Timeline/TrackKeyFrames.tsx b/app/pages/PageEnigma/comps/Timeline/TrackKeyFrames.tsx index 5035fec17..7cec6fffd 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackKeyFrames.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackKeyFrames.tsx @@ -24,7 +24,7 @@ export const TrackKeyFrames = ({ group, }: Props) => { return ( -
+
{ Queue.publish({ queueName: QueueNames.TO_ENGINE, action: toEngineActions.UPDATE_TIME, - data: { currentTime: Math.round(time) + currentScroll.value }, + data: { currentTime: Math.round(time) + timelineScrollX.value }, }); } }; @@ -46,7 +46,7 @@ export const useMouseEventsScrubber = () => { Queue.publish({ queueName: QueueNames.TO_ENGINE, action: toEngineActions.UPDATE_TIME, - data: { currentTime: delta + currentScroll.value }, + data: { currentTime: delta + timelineScrollX.value }, }); } return delta; diff --git a/app/pages/PageEnigma/comps/TimerGrid/TimerGrid.tsx b/app/pages/PageEnigma/comps/TimerGrid/TimerGrid.tsx deleted file mode 100644 index 6a160f689..000000000 --- a/app/pages/PageEnigma/comps/TimerGrid/TimerGrid.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { filmLength, fullHeight, scale } from "~/pages/PageEnigma/store"; -import { Fragment } from "react"; - -export const TimerGrid = () => { - const sectionWidth = 60 * 4 * scale.value; - - return ( -
- {Array(filmLength.value) - .fill(0) - .map((_, index) => ( - -
- 00:{index < 10 ? "0" + index.toString() : index.toString()} -
-
- - ))} -
- 00: - {filmLength.value < 10 - ? "0" + filmLength.value.toString() - : filmLength.value.toString()} -
-
-
- ); -}; diff --git a/app/pages/PageEnigma/store/objectGroup/objectGroup.ts b/app/pages/PageEnigma/store/objectGroup/objectGroup.ts index 5de11c02a..4fcc9ab30 100644 --- a/app/pages/PageEnigma/store/objectGroup/objectGroup.ts +++ b/app/pages/PageEnigma/store/objectGroup/objectGroup.ts @@ -73,7 +73,7 @@ export function deleteObjectKeyframe(keyframe: Keyframe) { const obj = oldObjectGroup.objects.find( (row) => row.object_uuid === keyframe.object_uuid, ); - console.log("delete", obj, keyframe.keyframe_uuid); + if (!obj) { return oldObjectGroup; } diff --git a/app/pages/PageEnigma/store/sizing.ts b/app/pages/PageEnigma/store/sizing.ts index 97a4e58b3..a49174129 100644 --- a/app/pages/PageEnigma/store/sizing.ts +++ b/app/pages/PageEnigma/store/sizing.ts @@ -9,7 +9,7 @@ export const timelineHeight = signal(0); export const fullHeight = computed(() => { return ( - characterGroup.value.length * 268 + + characterGroup.value.characters.length * 268 + objectGroup.value.objects.length * 60 + 300 + 96 diff --git a/app/pages/PageEnigma/store/timing.ts b/app/pages/PageEnigma/store/timing.ts index 482fa09c8..b36790e0c 100644 --- a/app/pages/PageEnigma/store/timing.ts +++ b/app/pages/PageEnigma/store/timing.ts @@ -2,4 +2,5 @@ import { signal } from "@preact/signals-core"; export const currentTime = signal(0); -export const currentScroll = signal(0); +export const timelineScrollX = signal(0); +export const timelineScrollY = signal(0);