Scroll timeline (#299)

scrolls selected item in the editor into view in the timeline

---------

Co-authored-by: Christopher Oliphant <RALifeCoach@users.noreply.github.com>
This commit is contained in:
FromTheLOLAshesandChristopher Oliphant authored and GitHub committed 2024-05-02 14:06:26 -04:00
1 parent b235b7bec7
commit 1a0f471f54
7 files changed
+85 -24

No files matched your search

@@ -33,8 +33,6 @@ export function StyleButtons() {
});
};
console.log("state", editorState.value);
return (
<div className="flex w-full flex-col justify-center gap-4 rounded-b-lg bg-ui-panel px-4">
<div className="w-full">
@@ -18,6 +18,7 @@ export const Audio = () => {
if (audioMinimized.value) {
return (
<div
id="track-global-audio"
className="relative flex h-[35px] items-center justify-end rounded-r-lg bg-global_audio-groupBg pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -38,6 +39,7 @@ export const Audio = () => {
return (
<div
id="track-global-audio"
className="relative block rounded-r-lg bg-global_audio-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -18,6 +18,7 @@ export const Camera = () => {
if (cameraMinimized.value) {
return (
<div
id="track-camera"
className="relative flex h-[35px] items-center justify-end rounded-r-lg bg-camera-groupBg pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -38,6 +39,7 @@ export const Camera = () => {
return (
<div
id="track-camera"
className="relative block rounded-r-lg bg-camera-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}>
<div className="flex justify-end">
@@ -62,7 +62,7 @@ export const Character = ({ character }: Props) => {
if (minimized) {
return (
<div
id={`character-${character.object_uuid}`}
id={`track-character-${character.object_uuid}`}
className="relative flex h-[35px] items-center justify-end rounded-r-lg bg-character-groupBg pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -83,6 +83,7 @@ export const Character = ({ character }: Props) => {
return (
<div
id={`track-character-${character.object_uuid}`}
className="relative block rounded-r-lg bg-character-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}>
<div className="flex h-[35px] items-center justify-end">
@@ -1,10 +1,9 @@
import {
audioMinimized,
cameraMinimized,
fullWidth,
minimizeIconPosition,
objectGroup,
objectsMinimized,
selectedObject,
} from "~/pages/PageEnigma/store";
import { useSignals } from "@preact/signals-react/runtime";
import { ObjectTrackComponent } from "~/pages/PageEnigma/comps/Timeline/ObjectTrack";
@@ -21,6 +20,7 @@ export const ObjectGroups = () => {
if (objectsMinimized.value) {
return (
<div
id="track-objects"
className="relative mb-4 flex h-[35px] items-center justify-end rounded-r-lg bg-object-groupBg pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -41,6 +41,7 @@ export const ObjectGroups = () => {
return (
<div
id="track-objects"
className="relative mb-5 block rounded-r-lg bg-object-groupBg pr-4"
style={{ width: fullWidth.value + 16 }}>
<button
@@ -57,7 +58,10 @@ export const ObjectGroups = () => {
</button>
<div className="pt-[47px]">
{objectGroup.value.objects.map((object) => (
<div key={object.object_uuid} className="pb-4 pr-4">
<div
key={object.object_uuid}
className="pb-4 pr-4"
id={`track-object-${selectedObject.value?.id}`}>
<ObjectTrackComponent object={object} />
</div>
))}
@@ -1,4 +1,4 @@
import { UIEvent, useCallback, useEffect, useState } from "react";
import { UIEvent, useCallback, useEffect, useRef, useState } from "react";
import { LowerPanel } from "~/modules/LowerPanel";
import { Camera } from "./Camera";
@@ -9,12 +9,14 @@ import {
deleteCharacterClip,
filmLength,
ignoreKeyDelete,
isHotkeyDisabled,
objectsMinimized,
scale,
selectedItem,
selectedObject,
timelineHeight,
timelineScrollX,
timelineScrollY,
isHotkeyDisabled,
} from "~/pages/PageEnigma/store";
import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler";
import { useSignals } from "@preact/signals-react/runtime";
@@ -23,7 +25,7 @@ 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 { AssetType, Clip, Keyframe } from "~/pages/PageEnigma/models";
import { RowHeaders } from "~/pages/PageEnigma/comps/Timeline/RowHeaders/RowHeaders";
import { pageWidth } from "~/store";
import { Pages } from "~/pages/PageEnigma/constants/page";
@@ -36,10 +38,38 @@ function getItemType(item: Clip | Keyframe | null) {
return (item as Clip).clip_uuid ? "clip" : "keyframe";
}
function scrollItem(itemId: string) {
const element = document.getElementById(itemId);
if (!element) {
return;
}
element.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
export const Timeline = () => {
useSignals();
const [dialogOpen, setDialogOpen] = useState(false);
const { deleteKeyframe } = useUpdateKeyframe();
const lastSelectedObject = useRef(selectedObject.value);
if (selectedObject.value !== lastSelectedObject.current) {
lastSelectedObject.current = selectedObject.value;
switch (selectedObject.value?.type) {
case AssetType.CHARACTER:
scrollItem(`track-character-${selectedObject.value?.id}`);
break;
case AssetType.CAMERA:
scrollItem("track-camera");
break;
case AssetType.OBJECT:
if (objectsMinimized.value) {
scrollItem("track-objects");
} else {
scrollItem(`track-object-${selectedObject.value?.id}`);
}
break;
}
}
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) => {
timelineScrollX.value = event.currentTarget.scrollLeft;
+39 -15
View File
@@ -35,7 +35,11 @@ import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
import { fromEngineActions } from "~/pages/PageEnigma/Queue/fromEngineActions";
import { AssetType, MediaItem } from "~/pages/PageEnigma/models";
import { loadingBarData, loadingBarIsShowing } from "~/store/loadingBar";
import { editorState, EditorStates, previewSrc } from "~/pages/PageEnigma/store/engine";
import {
editorState,
EditorStates,
previewSrc,
} from "~/pages/PageEnigma/store/engine";
// Main editor class that will call everything else all you need to call is " initialize() ".
class Editor {
@@ -317,7 +321,10 @@ class Editor {
this.renderer.setPixelRatio(window.devicePixelRatio);
//document.body.appendChild(this.renderer.domElement)
window.addEventListener("resize", this.onWindowResize.bind(this));
this.renderer.domElement.addEventListener("resize", this.onWindowResize.bind(this));
this.renderer.domElement.addEventListener(
"resize",
this.onWindowResize.bind(this),
);
this._configurePostProcessing();
// Controls and movement.
@@ -479,7 +486,7 @@ class Editor {
]);
}
public async testTestTimelineEvents() { }
public async testTestTimelineEvents() {}
public async loadScene(scene_media_token: string) {
this.dispatchAppUiState({
@@ -564,7 +571,11 @@ class Editor {
);
const timeline_json = await proxyTimeline.saveToJson();
const save_data = { version: this.version, scene: scene_json, timeline: timeline_json };
const save_data = {
version: this.version,
scene: scene_json,
timeline: timeline_json,
};
// TODO turn scene information into and object ...
const result = await this.api_manager.saveSceneState(
@@ -833,23 +844,29 @@ class Editor {
// Basicly Unity 3D's update loop.
async updateLoop() {
setTimeout(() => {
requestAnimationFrame(this.updateLoop.bind(this));
}, 1000 / (this.cap_fps * 2)); // Get the most FPS we can out of the renderer.
setTimeout(
() => {
requestAnimationFrame(this.updateLoop.bind(this));
},
1000 / (this.cap_fps * 2),
); // Get the most FPS we can out of the renderer.
if (this.container === undefined) {
this.container = document.getElementById("video-scene-container");
}
if (!this.rendering && this.container !== undefined) {
if (this.container.clientWidth + this.container.clientHeight !== this.lastCanvasSize) {
if (
this.container.clientWidth + this.container.clientHeight !==
this.lastCanvasSize
) {
this.onWindowResize();
this.lastCanvasSize = this.container.clientWidth + this.container.clientHeight;
this.lastCanvasSize =
this.container.clientWidth + this.container.clientHeight;
}
}
if (this.cam_obj == undefined) {
this.cam_obj = this.activeScene.get_object_by_name(this.camera_name);
}
// Updates debug stats.
@@ -969,10 +986,10 @@ class Editor {
audioSegment,
"-filter_complex",
"[1:a]adelay=" +
startTime * 1000 +
"|" +
startTime * 1000 +
"[a1];[0:a][a1]amix=inputs=2[a]",
startTime * 1000 +
"|" +
startTime * 1000 +
"[a1];[0:a][a1]amix=inputs=2[a]",
"-map",
"[a]",
`${itteration}final_tmp.wav`,
@@ -1461,6 +1478,13 @@ class Editor {
}
}
getAssetType(selected: THREE.Object3D<THREE.Object3DEventMap>): AssetType {
if (selected.type === "Mesh") {
return selected.name === "::CAM::" ? AssetType.CAMERA : AssetType.OBJECT;
}
return AssetType.CHARACTER;
}
publishSelect() {
if (this.selected) {
console.log("publish", this.selected);
@@ -1468,7 +1492,7 @@ class Editor {
queueName: QueueNames.FROM_ENGINE,
action: fromEngineActions.SELECT_OBJECT,
data: {
type: this.selected.type,
type: this.getAssetType(this.selected),
object_uuid: this.selected.uuid,
version: 1,
media_id: this.selected.id.toString(),