Skip to content

Commit

Permalink
Merge pull request #435 from charlielee/issue-393
Browse files Browse the repository at this point in the history
Implement playback speed selection
  • Loading branch information
charlielee committed Dec 17, 2022
2 parents 4289418 + 644046f commit a4bda07
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 13 deletions.
9 changes: 9 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,12 @@ export const stringToArray = (items: string) =>
items
.match(/[^\s"']+|"([^"]*)"/gim)
?.map((arg: string) => arg.replace(/"|'/g, ""));

export const PLAYBACK_SPEEDS = {
"0.1×": 0.1,
"0.25×": 0.25,
"0.5×": 0.5,
"1.0×": 1,
"2.0×": 2,
"4.0×": 4,
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Toolbar from "../../common/Toolbar/Toolbar";
import ToolbarItem, {
ToolbarItemAlign,
} from "../../common/ToolbarItem/ToolbarItem";
import PlaybackSpeedSelect from "../PlaybackSpeedSelect/PlaybackSpeedSelect";
import "./AnimationToolbar.css";

interface AnimationToolbarProps {
Expand Down Expand Up @@ -94,6 +95,7 @@ const AnimationToolbar = ({
</ToolbarItem>

<ToolbarItem stretch align={ToolbarItemAlign.RIGHT}>
<PlaybackSpeedSelect />
<IconButton
title={`${loopPlayback ? "Disable" : "Enable"} Loop Playback`}
icon={IconName.PLAY_LOOP}
Expand Down
9 changes: 5 additions & 4 deletions src/renderer/components/animator/Animator/Animator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@ const Animator = ({ take }: AnimatorWithProviderProps): JSX.Element => {
const AnimatorWithProvider = ({
take,
}: AnimatorWithProviderProps): JSX.Element => {
const shortPlayLength = useSelector(
(state: RootState) => state.app.userPreferences.shortPlayLength
);
const selectors = useSelector((state: RootState) => ({
shortPlayLength: state.app.userPreferences.shortPlayLength,
playbackSpeed: state.project.playbackSpeed,
}));

return (
<PlaybackContextProvider take={take} shortPlayLength={shortPlayLength}>
<PlaybackContextProvider take={take} {...selectors}>
<Animator take={take} />
</PlaybackContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useDispatch, useSelector } from "react-redux";
import { PLAYBACK_SPEEDS } from "../../../../common/utils";
import { setPlaybackSpeed } from "../../../redux/project/actions";
import { RootState } from "../../../redux/store";
import InputSelect from "../../common/Input/InputSelect/InputSelect";

const PlaybackSpeedSelect = (): JSX.Element => {
const dispatch = useDispatch();
const playbackSpeed = useSelector(
(state: RootState) => state.project.playbackSpeed
);

return (
<InputSelect
options={PLAYBACK_SPEEDS}
value={playbackSpeed}
onChange={(newValue) => dispatch(setPlaybackSpeed(parseFloat(newValue)))}
title={`Playback Speed ${playbackSpeed}x`}
fitContent
/>
);
};

export default PlaybackSpeedSelect;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

.input-select {
padding: var(--margin-025) var(--margin-150) var(--margin-025) var(--margin-050);
}

.input-select--fit-content {
max-width: fit-content;
}
29 changes: 23 additions & 6 deletions src/renderer/components/common/Input/InputSelect/InputSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
interface InputSelectProps {
import classNames from "classnames";
import "./InputSelect.css";

type InputSelectValue = string | number | undefined;

interface InputSelectProps<TValue> {
id?: string;
options: Record<string, string>;
value: string | undefined;
options: Record<string, TValue>;
value: TValue;
onChange(newValue: string): void;
title?: string;
fitContent?: boolean;
}

const InputSelect = ({
const InputSelect = <TValue extends InputSelectValue>({
id,
options,
onChange,
value,
}: InputSelectProps): JSX.Element => {
title,
fitContent,
}: InputSelectProps<TValue>): JSX.Element => {
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) =>
onChange(event.target.value);

return (
<select id={id} value={value} onChange={handleChange}>
<select
id={id}
value={value}
onChange={handleChange}
title={title}
className={classNames("input-select", {
"input-select--fit-content": fitContent,
})}
>
{Object.entries(options).map(([k, v]) => (
<option value={v} key={k}>
{k}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import PlaybackContext, {
interface PlaybackContextProviderProps {
shortPlayLength: FrameCount;
take: Take;
playbackSpeed: number;
children: ReactNode;
}

const PlaybackContextProvider = ({
shortPlayLength,
take,
playbackSpeed,
children,
}: PlaybackContextProviderProps) => {
const playForDuration = getTrackLength(take.frameTrack);
Expand All @@ -30,7 +32,7 @@ const PlaybackContextProvider = ({

const [liveViewVisible, setLiveViewVisible] = useState(true);

const delay = 1000 / take.frameRate;
const delay = 1000 / take.frameRate / playbackSpeed;
const previousTime = useRef<number>(0);
const lastFrameIndex = useRef<TimelineIndex>(0);

Expand Down
1 change: 1 addition & 0 deletions src/renderer/redux/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum AppActionType {
SET_CAMERA_ACCESS = "app/SET_CAMERA_ACCESS",
START_LOADING = "app/START_LOADING",
STOP_LOADING = "app/STOP_LOADING",
SET_PLAYBACK_SPEED = "app/SET_PLAYBACK_SPEED",
}

export type AppAction =
Expand Down
18 changes: 17 additions & 1 deletion src/renderer/redux/project/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ export enum ProjectActionType {
ADD_PROJECT = "project/ADD_PROJECT",
ADD_TAKE = "project/ADD_TAKE",
INCREMENT_EXPORTED_FRAME_NUMBER = "project/INCREMENT_EXPORTED_FRAME_NUMBER",
SET_PLAYBACK_SPEED = "project/SET_PLAYBACK_SPEED",
}

export type ProjectActions =
| AddFileRefAction
| AddFrameTrackAction
| AddTakeAction
| IncrementExportedFrameNumber;
| IncrementExportedFrameNumber
| SetPlaybackSpeed;

interface AddFileRefAction {
type: ProjectActionType.ADD_FILE_REF;
Expand All @@ -38,6 +40,13 @@ interface IncrementExportedFrameNumber {
type: ProjectActionType.INCREMENT_EXPORTED_FRAME_NUMBER;
}

interface SetPlaybackSpeed {
type: ProjectActionType.SET_PLAYBACK_SPEED;
payload: {
playbackSpeed: number;
};
}

export const addFileRef = (fileRef: FileRef) => ({
type: ProjectActionType.ADD_FILE_REF,
payload: { fileRef },
Expand All @@ -60,3 +69,10 @@ export const addFrameTrackItem = (trackItem: TrackItem) => ({
export const incrementExportedFrameNumber = () => ({
type: ProjectActionType.INCREMENT_EXPORTED_FRAME_NUMBER,
});

export const setPlaybackSpeed = (playbackSpeed: number) => ({
type: ProjectActionType.SET_PLAYBACK_SPEED,
payload: {
playbackSpeed,
},
});
6 changes: 6 additions & 0 deletions src/renderer/redux/project/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const projectReducer = (
lastExportedFrameNumber: state.take.lastExportedFrameNumber + 1,
},
};

case ProjectActionType.SET_PLAYBACK_SPEED:
return {
...state,
playbackSpeed: action.payload.playbackSpeed,
};
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/renderer/redux/project/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { Take } from "../../../common/project/Take";
export interface ProjectState {
fileRefs: FileRef[];
take?: Take;
playbackSpeed: number;
}

export const initialProjectState: ProjectState = {
fileRefs: [],
take: undefined,
playbackSpeed: 1,
};
1 change: 1 addition & 0 deletions src/renderer/styles/_sizes.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@
--margin-025: var(--width-4);
--margin-050: var(--width-8);
--margin-100: var(--width-16);
--margin-150: calc(var(--width-16) * 1.5);
}
3 changes: 2 additions & 1 deletion src/renderer/styles/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ textarea:focus {
select {
background-image: url("./images/dropdown.svg");
background-repeat: no-repeat;
background-position: right;
background-position: center right var(--margin-025);
background-size: 1rem;
}

table {
Expand Down

0 comments on commit a4bda07

Please sign in to comment.