diff --git a/src/pages/edit/Editor/components/FrameControl.tsx b/src/pages/edit/Editor/components/FrameControl.tsx index d44a059..b3a7858 100644 --- a/src/pages/edit/Editor/components/FrameControl.tsx +++ b/src/pages/edit/Editor/components/FrameControl.tsx @@ -1,59 +1,150 @@ import { ChevronLeft, ChevronRight } from "@mui/icons-material"; -import { IconButton, Paper } from "@mui/material"; +import { Box, IconButton, Paper, TextField, ToggleButton } from "@mui/material"; +import { useState } from "react"; +import { useInterval } from "react-use"; import { useComponentEditorStore } from "../store"; +import { + isValidPlaybackSpeed, + MAX_PLAYBACK_SPEED, + MIN_PLAYBACK_SPEED, +} from "../store/slices/core/types"; export default function CCComponentEditorFrameControl() { - const componentEditorState = useComponentEditorStore()(); + const componentEditorStore = useComponentEditorStore(); + const componentEditorState = componentEditorStore(); + const [speedInput, setSpeedInput] = useState( + String(componentEditorState.playbackSpeed), + ); + const isAutomatic = componentEditorState.playbackMode === "auto"; + const isSpeedValid = isValidPlaybackSpeed(Number(speedInput)); + + useInterval( + () => { + const state = componentEditorStore.getState(); + if (state.editorMode === "play" && state.playbackMode === "auto") { + state.setTimeStep(state.timeStep + 1); + } + }, + componentEditorState.editorMode === "play" && isAutomatic + ? 1000 / componentEditorState.playbackSpeed + : null, + ); if (componentEditorState.editorMode === "edit") return null; return ( - - { - componentEditorState.setTimeStep(componentEditorState.timeStep - 1); + - - - { - const value = Number.parseInt(e.target.value, 10); - if (!Number.isNaN(value) && value > 0) { - componentEditorState.setTimeStep(value - 1); + { + componentEditorState.setPlaybackMode( + isAutomatic ? "manual" : "auto", + ); + }} + > + Auto + + + { + componentEditorState.setTimeStep( + componentEditorState.timeStep - 1, + ); + }} + > + + + { + const value = Number(e.target.value); + if (Number.isSafeInteger(value) && value > 0) { + componentEditorState.setTimeStep(value - 1); + } + }} + /> + { + componentEditorState.setTimeStep( + componentEditorState.timeStep + 1, + ); + }} + > + + + + - { - componentEditorState.setTimeStep(componentEditorState.timeStep + 1); - }} - > - - - + slotProps={{ + htmlInput: { + min: MIN_PLAYBACK_SPEED, + max: MAX_PLAYBACK_SPEED, + step: "any", + }, + }} + onChange={(e) => { + setSpeedInput(e.target.value); + componentEditorState.setPlaybackSpeed(Number(e.target.value)); + }} + onBlur={() => { + setSpeedInput( + String(componentEditorStore.getState().playbackSpeed), + ); + }} + /> + + ); } diff --git a/src/pages/edit/Editor/renderer/Node/components/Display/ConfigSettingButton.tsx b/src/pages/edit/Editor/renderer/Node/components/Display/ConfigSettingButton.tsx index b44d29b..d72e591 100644 --- a/src/pages/edit/Editor/renderer/Node/components/Display/ConfigSettingButton.tsx +++ b/src/pages/edit/Editor/renderer/Node/components/Display/ConfigSettingButton.tsx @@ -3,6 +3,7 @@ import { Button, FormLabel, IconButton, + MenuItem, Popover, Stack, TextField, @@ -97,6 +98,23 @@ export function CCComponentEditorRendererNodeDisplayRendererConfigSettingButton( }} /> + { + const pixelOrder = e.target.value; + if (pixelOrder === "row-major" || pixelOrder === "column-major") { + setNewConfig((prev) => ({ ...prev, pixelOrder })); + } + }} + size="small" + fullWidth + sx={{ mt: 2 }} + > + Row-major + Column-major +