Browse Source

select new keyframe and three decimal values

Alejandro Toledo 5 years ago
parent
commit
eaf87307dd

+ 33 - 7
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -90,6 +90,7 @@ export class AnimationCurveEditorComponent extends React.Component<
         actionableKeyframe: IActionableKeyFrame;
         valueScale: CurveScale;
         canvasLength: number;
+        lastKeyframeCreated: Nullable<string>;
     }
 > {
     private _snippetUrl = "https://snippet.babylonjs.com";
@@ -179,6 +180,7 @@ export class AnimationCurveEditorComponent extends React.Component<
             repositionCanvas: false,
             actionableKeyframe: { frame: undefined, value: undefined },
             valueScale: CurveScale.default,
+            lastKeyframeCreated: null,
         };
     }
 
@@ -631,7 +633,16 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
-    setKeyframeValue() {
+    setKeyframeValueFromInput = (actionableKeyframe: IActionableKeyFrame) => {
+        this.setState(
+            {
+                actionableKeyframe,
+            },
+            this.setKeyframeValue
+        );
+    };
+
+    setKeyframeValue = () => {
         if (this.state.actionableKeyframe.frame !== "" && this.state.actionableKeyframe.frame !== undefined && this.state.actionableKeyframe.value !== "" && this.state.actionableKeyframe.value !== undefined) {
             if (this.state.selected !== null) {
                 let currentSelected = this.state.svgKeyframes?.find((kf) => kf.selected);
@@ -658,7 +669,7 @@ export class AnimationCurveEditorComponent extends React.Component<
                 }
             }
         }
-    }
+    };
 
     setFlatTangent() {
         const keyframes = this.state.svgKeyframes?.filter((kf) => kf.selected).map((k) => this.decodeCurveId(k.id));
@@ -749,13 +760,19 @@ export class AnimationCurveEditorComponent extends React.Component<
 
                 let actualValue = this.setValueAsType(currentAnimation.dataType, arrayValue);
 
-                keys.push({
+                const recentlyCreated = {
                     frame: x,
                     value: actualValue,
                     inTangent: emptyValue,
                     outTangent: emptyValue,
-                });
+                };
+
+                keys.push(recentlyCreated);
                 keys.sort((a, b) => a.frame - b.frame);
+                const newIndex = keys.findIndex((kf) => kf.frame === x);
+                const id = `${currentAnimation.name}_${currentAnimation.targetProperty}_${this.state.selectedCoordinate}`;
+                const curvedId = this.encodeCurveId(id, newIndex);
+                this.setState({ lastKeyframeCreated: curvedId });
 
                 currentAnimation.setKeys(keys);
 
@@ -1316,12 +1333,21 @@ export class AnimationCurveEditorComponent extends React.Component<
                 selectedCoordinate: selectedCurve,
                 fps: animation.framePerSecond,
             },
-            () => this.setMainAnimatable()
+            this.postSelectionEvents
         );
     }
 
+    postSelectionEvents = () => {
+        if (this.state.lastKeyframeCreated !== null) {
+            this.deselectKeyframes();
+            this.selectKeyframe(this.state.lastKeyframeCreated, false);
+        }
+
+        this.setMainAnimatable();
+    };
+
     setMainAnimatable() {
-        if (this.state.selected) {
+        if (this.state.selected !== null) {
             let target = this.props.entity;
             if (this.props.entity instanceof TargetedAnimation) {
                 target = this.props.entity.target;
@@ -1531,7 +1557,7 @@ export class AnimationCurveEditorComponent extends React.Component<
             <div ref={this._editor} id="animation-curve-editor">
                 <Notification message={this.state.notification} open={this.state.notification !== "" ? true : false} close={() => this.clearNotification()} />
                 <GraphActionsBar
-                    setKeyframeValue={() => this.setKeyframeValue()}
+                    setKeyframeValue={this.setKeyframeValueFromInput}
                     enabled={this.state.selected === null || this.state.selected === undefined ? false : true}
                     title={this._entityName}
                     close={this.props.close}

+ 120 - 119
inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx

@@ -1,132 +1,133 @@
-import * as React from 'react';
-import { IconButtonLineComponent } from '../../../lines/iconButtonLineComponent';
-import { IActionableKeyFrame } from './animationCurveEditorComponent';
+import * as React from "react";
+import { IconButtonLineComponent } from "../../../lines/iconButtonLineComponent";
+import { IActionableKeyFrame } from "./animationCurveEditorComponent";
 
 interface IGraphActionsBarProps {
-  addKeyframe: () => void;
-  removeKeyframe: () => void;
-  handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
-  handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
-  flatTangent: () => void;
-  brokeTangents: () => void;
-  setLerpMode: () => void;
-  brokenMode: boolean;
-  lerpMode: boolean;
-  actionableKeyframe: IActionableKeyFrame;
-  title: string;
-  close: (event: any) => void;
-  enabled: boolean;
-  setKeyframeValue: () => void;
+    addKeyframe: () => void;
+    removeKeyframe: () => void;
+    handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+    handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+    flatTangent: () => void;
+    brokeTangents: () => void;
+    setLerpMode: () => void;
+    brokenMode: boolean;
+    lerpMode: boolean;
+    actionableKeyframe: IActionableKeyFrame;
+    title: string;
+    close: (event: any) => void;
+    enabled: boolean;
+    setKeyframeValue: (actionableKeyframe: IActionableKeyFrame) => void;
 }
 
-export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
-  private _frameInput: React.RefObject<HTMLInputElement>;
-  private _valueInput: React.RefObject<HTMLInputElement>;
-  constructor(props: IGraphActionsBarProps) {
-    super(props);
-    this._frameInput = React.createRef();
-    this._valueInput = React.createRef();
-  }
+export class GraphActionsBar extends React.Component<IGraphActionsBarProps, { frame: string; value: string }> {
+    private _frameInput: React.RefObject<HTMLInputElement>;
+    private _valueInput: React.RefObject<HTMLInputElement>;
+    constructor(props: IGraphActionsBarProps) {
+        super(props);
+        this._frameInput = React.createRef();
+        this._valueInput = React.createRef();
+        const { frame, value } = this.selectedKeyframeChanged(this.props.actionableKeyframe);
+        this.state = { frame, value };
+    }
+
+    componentDidMount() {
+        this._frameInput.current?.addEventListener("keyup", this.isEnterKeyUp.bind(this));
+        this._valueInput.current?.addEventListener("keyup", this.isEnterKeyUp.bind(this));
+    }
+
+    componentDidUpdate(prevProps: IGraphActionsBarProps, prevState: any) {
+        if (prevProps.actionableKeyframe !== this.props.actionableKeyframe) {
+            const { frame, value } = this.selectedKeyframeChanged(this.props.actionableKeyframe);
+            this.setState({ frame, value });
+        }
+    }
 
-  componentDidMount() {
-    this._frameInput.current?.addEventListener(
-      'keyup',
-      this.isEnterKeyUp.bind(this)
-    );
-    this._valueInput.current?.addEventListener(
-      'keyup',
-      this.isEnterKeyUp.bind(this)
-    );
-  }
+    selectedKeyframeChanged(keyframe: IActionableKeyFrame) {
+        let frame = "";
+        if (typeof keyframe.frame === "number") {
+            frame = keyframe.frame.toString();
+        }
+        let value = "";
+        if (typeof keyframe.value === "number") {
+            value = keyframe.value.toFixed(3);
+        }
+        return { frame, value };
+    }
 
-  componentWillUnmount() {
-    this._frameInput.current?.removeEventListener(
-      'keyup',
-      this.isEnterKeyUp.bind(this)
-    );
-    this._valueInput.current?.removeEventListener(
-      'keyup',
-      this.isEnterKeyUp.bind(this)
-    );
-  }
+    componentWillUnmount() {
+        this._frameInput.current?.removeEventListener("keyup", this.isEnterKeyUp.bind(this));
+        this._valueInput.current?.removeEventListener("keyup", this.isEnterKeyUp.bind(this));
+    }
 
-  isEnterKeyUp(event: KeyboardEvent) {
-    event.preventDefault();
+    isEnterKeyUp(event: KeyboardEvent) {
+        event.preventDefault();
 
-    if (event.key === 'Enter') {
-      this.props.setKeyframeValue();
+        if (event.key === "Enter") {
+            const actionableKeyframe: IActionableKeyFrame = { frame: this.getFrame(), value: this.getValue() };
+            this.props.setKeyframeValue(actionableKeyframe);
+        }
     }
-  }
 
-  onBlur(event: React.FocusEvent<HTMLInputElement>) {
-    event.preventDefault();
-    if (event.target.value !== '') {
-      this.props.setKeyframeValue();
+    onBlur(event: React.FocusEvent<HTMLInputElement>) {
+        event.preventDefault();
+        if (event.target.value !== "") {
+            const actionableKeyframe: IActionableKeyFrame = { frame: this.getFrame(), value: this.getValue() };
+            this.props.setKeyframeValue(actionableKeyframe);
+        }
     }
-  }
 
-  render() {
-    return (
-      <div className='actions-wrapper'>
-        <div className='title-container'>
-          <div className='icon babylon-logo'></div>
-          <div className='title'>{this.props.title}</div>
-        </div>
-        <div
-          className='buttons-container'
-          style={{ pointerEvents: this.props.enabled ? 'all' : 'none' }}
-        >
-          <div className='action-input frame-input'>
-            <input
-              ref={this._frameInput}
-              type='number'
-              onChange={this.props.handleFrameChange}
-              value={this.props.actionableKeyframe.frame?.toString() || ''}
-              step='1'
-              disabled={this.props.actionableKeyframe.frame === undefined}
-              onBlur={(e) => this.onBlur(e)}
-            />
-          </div>
-          <div className='action-input'>
-            <input
-              ref={this._valueInput}
-              type='number'
-              value={this.props.actionableKeyframe.value || ''}
-              onChange={this.props.handleValueChange}
-              step='0.01'
-              disabled={this.props.actionableKeyframe.value === undefined}
-              onBlur={(e) => this.onBlur(e)}
-            />
-          </div>
-          <IconButtonLineComponent
-            tooltip={'Add Keyframe'}
-            icon='new-key'
-            onClick={this.props.addKeyframe}
-          />
-          <IconButtonLineComponent
-            tooltip={'Frame selected keyframes'}
-            icon='frame'
-            onClick={this.props.removeKeyframe}
-          />
-          <IconButtonLineComponent
-            tooltip={'Flat Tangents'}
-            icon='flat-tangent'
-            onClick={this.props.flatTangent}
-          />
-          <IconButtonLineComponent
-            tooltip={
-              this.props.brokenMode ? 'Broken Mode On' : 'Broken Mode Off'
-            }
-            icon={this.props.brokenMode ? 'break-tangent' : 'unify-tangent'}
-            onClick={this.props.brokeTangents}
-          />
-          <IconButtonLineComponent
-            tooltip={this.props.lerpMode ? 'Lerp On' : 'lerp Off'}
-            icon='linear-tangent'
-            onClick={this.props.setLerpMode}
-          />
-        </div>
-      </div>
-    );
-  }
+    getFrame() {
+        let frame;
+        if (this.state.frame === "") {
+            frame = "";
+        } else {
+            frame = parseInt(this.state.frame);
+        }
+
+        return frame;
+    }
+
+    getValue() {
+        let value;
+        if (this.state.value !== "") {
+            value = parseFloat(this.state.value);
+        } else {
+            value = "";
+        }
+        return value;
+    }
+
+    handleValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+        e.preventDefault();
+        this.setState({ value: e.target.value });
+    };
+
+    handleFrameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+        e.preventDefault();
+        this.setState({ frame: e.target.value });
+    };
+
+    render() {
+        return (
+            <div className="actions-wrapper">
+                <div className="title-container">
+                    <div className="icon babylon-logo"></div>
+                    <div className="title">{this.props.title}</div>
+                </div>
+                <div className="buttons-container" style={{ pointerEvents: this.props.enabled ? "all" : "none" }}>
+                    <div className="action-input frame-input">
+                        <input ref={this._frameInput} type="number" onChange={this.handleFrameChange} value={this.state.frame} step="1" disabled={this.props.actionableKeyframe.frame === undefined} onBlur={(e) => this.onBlur(e)} />
+                    </div>
+                    <div className="action-input">
+                        <input ref={this._valueInput} type="number" value={this.state.value} onChange={this.handleValueChange} step="0.01" disabled={this.props.actionableKeyframe.value === undefined} onBlur={(e) => this.onBlur(e)} />
+                    </div>
+                    <IconButtonLineComponent tooltip={"Add Keyframe"} icon="new-key" onClick={this.props.addKeyframe} />
+                    <IconButtonLineComponent tooltip={"Frame selected keyframes"} icon="frame" onClick={this.props.removeKeyframe} />
+                    <IconButtonLineComponent tooltip={"Flat Tangents"} icon="flat-tangent" onClick={this.props.flatTangent} />
+                    <IconButtonLineComponent tooltip={this.props.brokenMode ? "Broken Mode On" : "Broken Mode Off"} icon={this.props.brokenMode ? "break-tangent" : "unify-tangent"} onClick={this.props.brokeTangents} />
+                    <IconButtonLineComponent tooltip={this.props.lerpMode ? "Lerp On" : "lerp Off"} icon="linear-tangent" onClick={this.props.setLerpMode} />
+                </div>
+            </div>
+        );
+    }
 }