Files
GacUI/TODO_Animation.md
2018-01-21 13:03:08 -08:00

144 lines
5.6 KiB
Markdown

## Animation (continuation)
### Goal
- Provide XML-defined interpolation function
- Provide new animation API
### Demo
- Download with round progress bar
- First X seconds the animation fill the progress bar
- After that if the downloading is not finished, show a rolling animation
- When the downloading is finished, show a ending animation
- Downloaded text fade in
- Progress bar fly out
### Feature
#### Interpolation function
A new xml tag will be added in <instance> to write a function:
- `func <NAME>(start: T, end: T, target: T): IGuiGraphicsAnimationInterpolation^;`
- `func <NAME>(start: T, end: T, target: U): IGuiGraphicsAnimationInterpolation^;`
- if T is a value type so it has to be change a property of type T in U
```
interface IGuiGraphicsAnimationInterpolation
{
func Interpolate(position: double):void;
}
```
#### API
- A group of new overloading functions are added in `GuiInstanceRootObject` which do
- Add animation to `root->GetControlHostInternal()->GetGraphicsHost()->GetAnimationManager()`, where `GetControlHostInternal` is a new protected abstract function.
- If the control host is not ready (e.g. the control has not been added to a window), then all animations will be kept and attach to the window later
- When the root object is deleted, all animations are stopped (set the internal flag so that the animation manager will remove them later)
- And has the following options:
- **interpolation object**
- **timed or infinite**
- for timed animation
- **a function** to convert passed total time to a double value
- default: `passed total time / total time`
- **a fomular** function to convert a double value from `[0..1]` to `[0..1]` to control the animation behavior
- for infinite animation
- **a function** to convert passed total time to a double value
- default: `passed total time`
- **end of animation notification**
- Stop an `IAsync` object
- Call a callback function
#### Workflow
- Author calls animation APIs themselves to start an animation
- State machine or async coroutine is supported by "end of animation notification"
- Add `$Await GetApplication().DoEvents();`
## Proposal (2)
```xml
<TimedAnimation Progress="progress"> <!-- Progress's default value is "progress" -->
<Interpolation> <!-- Interpolation's default value is "{ return progress; }" -->
<!CData[
{
var pi = 2 * Math::ASin(1);
return (Math::Sin((progress - 0.5) * pi) + 1) / 2;
}
]]>
</Interpolation>
<Data Name="Color" Type="Color"/>
<Data Name="Distance" Type="int"/> <!-- Data has its own Interpolation child element -->
<States Default="A">
<State Name="A">
<Data Name="Color" Value="#FF0000"/>
<Data Name="Distance" Value="0"/>
</State>
<State Name="B">
<Data Name="Color" Value="#FFFFFF"/>
<Data Name="Distance" Value="100"/>
</State>
</States>
<!--
Generate component:
class State{ /* all properties */ }
property Current : State^ {const, not observe}
property Source : State^ {const, not observe}
property Target : State^ {const, not observe}
property A : State^ {const, not observe}
property B : State^ {const, not observe}
func CreateAnimation(source:State^, target:State^, length:int):IGuiGraphicsAnimation^;
func ContinueAnimation(source:State^, target:State^, length:int):IGuiGraphicsAnimation^;
func GetAnimationLengthScale(source:State^, target:State^, current:State^):double;
func Interpolate(source:State^, target:State^, current:State^, progress:double):void;
-->
</TimedAnimation>
<InfiniteAnimation>
</InfiniteAnimation>
```
## Proposal (3)
- Remove `<InfiniteAnimation>`
- Add `Type="Once|Repeat"` to `<TimedAnimation>`
- All `<State>` should set exactly the same set of properties
- All properties that are not set in `<State>` should have a `Value` property, which is similar to `Interpolation`
- `Property Value` = `Value`(`Interpolation`((`CurrentTime` - `StartTime`) % `Length` / cast double `Length`))
- (optional) Syntax for `$switch` to wait for callbacks caused from some actions in the `$init` block
- (optional) Syntax for `$switch` to raise a specified exception for wrong inputs
```
try
{
$switch(raise "Sad!")
{
$init
{
DownloadAsync().Execute([$1; this.Cancel(); ], null);
}
case A():{}
case B():{}
}
}
catch(ex)
{
if (ex.Message == "Sad!") { return; }
raise;
}
```
## Proposal (4)
- Use XML to compose gradient timed animations as building blocks
- Use coroutine to compose complex animation
- **$AwaitTask**: await a task
- **$Play**: initiate and await an animation
- **$PlayInGroup**: initiate an animation but not wait, a group object (maybe just a number) should be provided
- **$AwaitGroup**: await all animations in a group
- **$Pause**: wait for several milliseconds
- If an animation is cancelled, all animations initiated by this animation are cancelled
- Animation manager object in the control host becomes a animation timer callback
- When a root object begins an animation, it attaches the callback object to the manager
- When a root object finishes an animation, it detaches the callback object from the manager
- When a root object is removed from a control host, it detaches the callback object from the manager, and create a new callback object when it is added to a control host later. Durint the moment, the animation is paused.
- Detach an callback object by setting the return value of function "Run" to false, and let the animation manager remove this object later.