Skip to content

Commit

Permalink
(from automaton-with-gui repo) Merge pull request #14 from FMS-Cat/cr…
Browse files Browse the repository at this point in the history
…eate-new-button

ChannelList/CurveList: create new button
  • Loading branch information
Yutaka Obuchi authored Apr 23, 2020
2 parents 53808a9 + dc866b5 commit 5c1aa79
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/AutomatonWithGUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ export class AutomatonWithGUI extends Automaton
* @param index Index of the curve
*/
public removeCurve( index: number ): void {
delete this.__curves[ index ];
this.__curves.splice( index, 1 );

this.__emit( 'removeCurve', { index } );

Expand Down
8 changes: 8 additions & 0 deletions src/view/components/AutomatonStateListener.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ const AutomatonStateListener = ( props: AutomatonStateListenerProps ): JSX.Eleme
createCurve( event.index, event.curve );
} );

const handleRemoveCurve = automaton.on( 'removeCurve', ( event ) => {
dispatch( {
type: 'Automaton/RemoveCurve',
curve: event.index
} );
} );

const handleChangeShouldSave = automaton.on( 'changeShouldSave', ( event ) => {
dispatch( {
type: 'Automaton/SetShouldSave',
Expand All @@ -387,6 +394,7 @@ const AutomatonStateListener = ( props: AutomatonStateListenerProps ): JSX.Eleme
automaton.off( 'createChannel', handleCreateChannel );
automaton.off( 'removeChannel', handleRemoveChannel );
automaton.off( 'createCurve', handleCreateCurve );
automaton.off( 'removeCurve', handleRemoveCurve );
automaton.off( 'changeShouldSave', handleChangeShouldSave );
};
},
Expand Down
84 changes: 80 additions & 4 deletions src/view/components/ChannelList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
import React, { useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from '../states/store';
import { ChannelListEntry } from './ChannelListEntry';
import { Colors } from '../constants/Colors';
import { Icons } from '../icons/Icons';
import styled from 'styled-components';
import { useSelector } from '../states/store';

// == styles =======================================================================================
const NewChannelIcon = styled.img`
fill: ${ Colors.gray };
height: 16px;
`;

const NewChannelButton = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 20px;
margin: 2px 0;
cursor: pointer;
background: ${ Colors.back3 };
&:active {
background: ${ Colors.back4 };
}
`;

const StyledChannelListEntry = styled( ChannelListEntry )`
width: 100%;
margin: 0.125rem 0;
height: 20px;
margin: 2px 0;
cursor: pointer;
`;

Expand All @@ -19,10 +42,57 @@ export interface ChannelListProps {
}

const ChannelList = ( { className }: ChannelListProps ): JSX.Element => {
const { channelNames } = useSelector( ( state ) => ( {
const dispatch = useDispatch();
const {
automaton,
channelNames
} = useSelector( ( state ) => ( {
automaton: state.automaton.instance,
channelNames: state.automaton.channelNames
} ) );

const handleClickNewChannel = useCallback(
( event: React.MouseEvent ) => {
if ( !automaton ) { return; }

dispatch( {
type: 'TextPrompt/Open',
position: { x: event.clientX, y: event.clientY },
placeholder: 'Name for the new channel',
checkValid: ( name ) => {
if ( name === '' ) { return false; }
if ( automaton.getChannel( name ) != null ) { return false; }
return true;
},
callback: ( name ) => {
const redo = (): void => {
automaton.createChannel( name );

dispatch( {
type: 'Timeline/SelectChannel',
channel: name
} );
};

const undo = (): void => {
automaton.removeChannel( name );
};

dispatch( {
type: 'History/Push',
entry: {
description: `Create Channel: ${ name }`,
redo,
undo
}
} );
redo();
}
} );
},
[ automaton ]
);

const sortedChannelNames = useMemo(
() => Array.from( channelNames ).sort(),
[ channelNames ]
Expand All @@ -36,6 +106,12 @@ const ChannelList = ( { className }: ChannelListProps ): JSX.Element => {
name={ channel }
/>
) ) }
<NewChannelButton
data-stalker="Create a new channel"
onClick={ handleClickNewChannel }
>
<NewChannelIcon as={ Icons.Plus } />
</NewChannelButton>
</Root>
);
};
Expand Down
1 change: 0 additions & 1 deletion src/view/components/ChannelListEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ const Icon = styled.img`

const Root = styled.div<{ isSelected: boolean }>`
position: relative;
height: 1.25rem;
background: ${ ( { isSelected } ) => ( isSelected ? Colors.back4 : Colors.back3 ) };
`;

Expand Down
80 changes: 75 additions & 5 deletions src/view/components/CurveList.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from '../states/store';

import { Colors } from '../constants/Colors';
import { CurveListEntry } from './CurveListEntry';
import React from 'react';
import { Icons } from '../icons/Icons';
import { Metrics } from '../constants/Metrics';
import { Scrollable } from './Scrollable';
import styled from 'styled-components';
import { useSelector } from '../states/store';

// == styles =======================================================================================
const NewCurveIcon = styled.img`
fill: ${ Colors.gray };
height: 16px;
`;

const NewCurveButton = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: ${ Metrics.curveListEntryHeight }px;
margin: 2px;
cursor: pointer;
background: ${ Colors.back3 };
&:active {
background: ${ Colors.back4 };
}
`;

const StyledCurveListEntry = styled( CurveListEntry )`
width: calc( 100% - 0.25rem );
margin: 0.125rem;
width: calc( 100% - 4px );
height: ${ Metrics.curveListEntryHeight }px;
margin: 2px;
cursor: pointer;
`;

Expand All @@ -22,10 +46,50 @@ export interface CurveListProps {
}

const CurveList = ( { className }: CurveListProps ): JSX.Element => {
const { curves } = useSelector( ( state ) => ( {
const dispatch = useDispatch();
const { automaton, curves } = useSelector( ( state ) => ( {
automaton: state.automaton.instance,
curves: state.automaton.curves
} ) );

const handleClickNewCurve = useCallback(
() => {
if ( !automaton ) { return; }

const curve = automaton.createCurve();
const index = automaton.getCurveIndex( curve );

const redo = (): void => {
const curve = automaton.createCurve();
const index = automaton.getCurveIndex( curve );

dispatch( {
type: 'CurveEditor/SelectCurve',
curve: index
} );
};

const undo = (): void => {
automaton.removeCurve( index );
};

dispatch( {
type: 'History/Push',
entry: {
description: 'Create Curve',
redo,
undo
}
} );

dispatch( {
type: 'CurveEditor/SelectCurve',
curve: index
} );
},
[ automaton ]
);

return (
<Root className={ className } barPosition='left'>
{ curves.map( ( curve, iCurve ) => (
Expand All @@ -34,6 +98,12 @@ const CurveList = ( { className }: CurveListProps ): JSX.Element => {
index={ iCurve }
/>
) ) }
<NewCurveButton
data-stalker="Create a new curve"
onClick={ handleClickNewCurve }
>
<NewCurveIcon as={ Icons.Plus } />
</NewCurveButton>
</Root>
);
};
Expand Down
2 changes: 0 additions & 2 deletions src/view/components/CurveListEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useDispatch, useSelector } from '../states/store';
import { Colors } from '../constants/Colors';
import { CurveStatusLevel } from '../../CurveWithGUI';
import { Icons } from '../icons/Icons';
import { Metrics } from '../constants/Metrics';
import styled from 'styled-components';

// == styles =======================================================================================
Expand All @@ -30,7 +29,6 @@ const Icon = styled.img`

const Root = styled.div<{ isSelected: boolean }>`
position: relative;
height: ${ Metrics.curveListEntryHeight }px;
background: ${ ( { isSelected } ) => ( isSelected ? Colors.back4 : Colors.back3 ) };
`;

Expand Down
1 change: 1 addition & 0 deletions src/view/icons/Icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const Icons = {
Error: require( './error.svg' ).default,
Pause: require( './pause.svg' ).default,
Play: require( './play.svg' ).default,
Plus: require( './plus.svg' ).default,
Redo: require( './redo.svg' ).default,
Save: require( './save.svg' ).default,
Snap: require( './snap.svg' ).default,
Expand Down
7 changes: 7 additions & 0 deletions src/view/icons/plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/view/states/Automaton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ export type Action = {
curve: number;
length: number;
path: string;
} | {
type: 'Automaton/RemoveCurve';
curve: number;
} | {
type: 'Automaton/UpdateCurvePath';
curve: number;
Expand Down Expand Up @@ -202,6 +205,8 @@ export const reducer: Reducer<State, Action> = ( state = initialState, action )
previewTime: null,
previewValue: null
};
} else if ( action.type === 'Automaton/RemoveCurve' ) {
newState.curves.splice( action.curve, 1 );
} else if ( action.type === 'Automaton/UpdateCurvePath' ) {
newState.curves[ action.curve ].path = action.path;
} else if ( action.type === 'Automaton/UpdateCurveStatus' ) {
Expand Down
4 changes: 4 additions & 0 deletions src/view/states/CurveEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ export const reducer: Reducer<State, ContextAction> = ( state = initialState, ac
if ( length < newState.range.t1 ) {
newState.range.t1 = length;
}
} else if ( action.type === 'Automaton/RemoveCurve' ) {
if ( state.selectedCurve === action.curve ) {
newState.selectedCurve = null;
}
} else if ( action.type === 'Automaton/RemoveCurveNode' ) {
newState.selectedItems.nodes = arraySetDiff( newState.selectedItems.nodes, [ action.id ] );
} else if ( action.type === 'Automaton/RemoveCurveFx' ) {
Expand Down

0 comments on commit 5c1aa79

Please sign in to comment.