-
-
Notifications
You must be signed in to change notification settings - Fork 8
Custom animation #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JasonBSteele
wants to merge
23
commits into
winleafs:master
Choose a base branch
from
JasonBSteele:custom-animation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Custom animation #199
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
949a671
Fixed PercentageProfile
JasonBSteele 6d5eb1b
Added CreateEffectWindow and opened it from MainWindow
JasonBSteele de42ade
Created FrameUserControl
JasonBSteele f06f619
Add and use the CustomEffect and Frames models
JasonBSteele 7cb2323
Added color picker
JasonBSteele 32cd086
Build the pallete of used colors
JasonBSteele 4ad4474
Created panel to Brush mapping and passed it to the panel layout
JasonBSteele c026e39
Fix missing black brush
JasonBSteele 484e557
Add Transition time and Play button
JasonBSteele fcccf4d
Added API calls for writing a custom effects
JasonBSteele c7253d1
Added the CustomEffectCommandBuilder
JasonBSteele dfff735
Added lock to the CustomEffectCommandBuilder
JasonBSteele db33de8
tidying
JasonBSteele 7b12074
Called the API!
JasonBSteele f7c0e24
Save to Device and cosmetics
JasonBSteele 35b2585
Use a ListBox for the Frames instead
JasonBSteele 9c7ddcf
minor bug and remove deleted code
JasonBSteele 5e63c8e
Tidying
JasonBSteele 26c0e2f
Added english text for the NL resource strings
JasonBSteele 1a5e6d3
PR feedback changes
JasonBSteele 01aa821
Change the Play button to a stop button after it is clicked
JasonBSteele e87ed76
Added comment for commented out code reason
JasonBSteele 07c131f
Remove currently selected frame rather than last
JasonBSteele File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| using Newtonsoft.Json; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace Winleafs.Models.Models.Effects | ||
| { | ||
| public class CustomEffectCommand | ||
| { | ||
| /// <summary> | ||
| /// The command can be either be add, update or display: | ||
| /// add - will create a new custom effect, or update one if it has the same animName | ||
| /// update - will update an existing effect with the same animName | ||
| /// display - will show the effect on the device but will not save it | ||
| /// </summary> | ||
| [JsonProperty("command")] | ||
| public string Command { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The version of the JSON schema. | ||
| /// </summary> | ||
| [JsonProperty("version")] | ||
| public string Version { get; } = "1.0"; | ||
|
|
||
| /// <summary> | ||
| /// The name of the custom effect | ||
| /// </summary> | ||
| [JsonProperty("animName")] | ||
| public string AnimName { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The type of animation, can be either custom or static. | ||
| /// </summary> | ||
| [JsonProperty("animType")] | ||
| public string AnimType { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// A data structure that specifies the speed at which frames transition from coor to color. | ||
| /// See 3.2.6.1 Custom effect at https://forum.nanoleaf.me/docs/openapi for more information. | ||
| /// </summary> | ||
| [JsonProperty("animData")] | ||
| public string AnimData { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Determines whether the custom effect will repeat. | ||
| /// </summary> | ||
| [JsonProperty("loop")] | ||
| public bool Loop { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// This has no functional use for the custom effect, it just sets | ||
| /// the colors to be displayed in apps that list the effect. | ||
| /// </summary> | ||
| [JsonProperty("palette")] | ||
| public IList<Palette> Palette { get; set; } = new List<Palette>(); | ||
| } | ||
| } |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Winleafs.Models.Models.Layouts | ||
| { | ||
| /// <summary> | ||
| /// A user created Custom Effect which specifies a static pattern or animation | ||
| /// </summary> | ||
| public class CustomEffect | ||
| { | ||
| /// <summary> | ||
| /// True if this is just one Frame to set each panel's color | ||
| /// </summary> | ||
| public bool IsStatic { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// True if the animation is played repeatedly | ||
| /// </summary> | ||
| public bool IsLoop { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// A series of frames each specifying the color for each panel | ||
| /// </summary> | ||
| public IList<Frame> Frames { get; set; } | ||
|
|
||
| public CustomEffect() | ||
| { | ||
| Frames = new List<Frame>(); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Winleafs.Models.Models.Layouts | ||
| { | ||
| public class Frame | ||
| { | ||
| public IDictionary<int, uint> PanelColors { get; set; } | ||
|
|
||
| public Frame() | ||
| { | ||
| PanelColors = new Dictionary<int, uint>(); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| using Winleafs.Models.Models.Layouts; | ||
|
|
||
| namespace Winleafs.Models.Models.Layouts | ||
| { | ||
| public class FrameListItem | ||
| { | ||
| public FrameListItem(Frame frame, string name) | ||
| { | ||
| Frame = frame; | ||
| Name = name; | ||
| } | ||
|
|
||
| public string Name { get; set; } | ||
| public Frame Frame { get; set; } | ||
| } | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
| using Winleafs.Models.Models.Effects; | ||
| using Winleafs.Models.Models.Layouts; | ||
| using Winleafs.Wpf.Helpers; | ||
|
|
||
| namespace Winleafs.Wpf.Api.Effects | ||
| { | ||
| /// <summary> | ||
| /// Used to build a CustomEffectCommand to send to the API | ||
| /// </summary> | ||
| public class CustomEffectCommandBuilder | ||
| { | ||
| private readonly CustomEffect _customEffect; | ||
| private int _transitionTime; | ||
|
|
||
| public CustomEffectCommandBuilder(CustomEffect customEffect) | ||
| { | ||
| _customEffect = customEffect; | ||
| } | ||
|
|
||
| public CustomEffectCommand BuildAddCommand(float transitionSecs, string name) | ||
| { | ||
| //If a name has been passed the custom effect will be added to the device | ||
| var customEffectCommand = new CustomEffectCommand(); | ||
| customEffectCommand.Command = "add"; | ||
| customEffectCommand.AnimName = name; | ||
|
|
||
| //Convert seconds to tenths of a second, the time unit used by commands | ||
| _transitionTime = (int)Math.Floor(transitionSecs * 10); | ||
|
|
||
| BuildBody(customEffectCommand); | ||
|
|
||
| return customEffectCommand; | ||
| } | ||
|
|
||
| public CustomEffectCommand BuildDisplayCommand(float transitionSecs) | ||
| { | ||
| //If no name has been passed the custom effect will just be dispayed on the device | ||
| var customEffectCommand = new CustomEffectCommand(); | ||
| customEffectCommand.Command = "display"; | ||
|
|
||
| //Convert seconds to tenths of a second, the time unit used by commands | ||
| _transitionTime = (int)Math.Floor(transitionSecs * 10); | ||
|
|
||
| BuildBody(customEffectCommand); | ||
|
|
||
| return customEffectCommand; | ||
| } | ||
|
|
||
| private void BuildBody(CustomEffectCommand customEffectCommand) | ||
| { | ||
| if (_customEffect.IsStatic) | ||
| { | ||
| customEffectCommand.AnimType = "static"; | ||
| } | ||
| else | ||
| { | ||
| customEffectCommand.AnimType = "custom"; | ||
| customEffectCommand.Loop = _customEffect.IsLoop; | ||
| } | ||
|
|
||
| var animData = new StringBuilder(); | ||
| animData.Append(_customEffect.Frames[0].PanelColors.Count); | ||
|
|
||
| foreach (var panelId in _customEffect.Frames[0].PanelColors.Keys) | ||
| { | ||
| animData.Append(BuildPanelAnimData(panelId)); | ||
| } | ||
|
|
||
| customEffectCommand.AnimData = animData.ToString(); | ||
|
|
||
| //Set pallete so used colurs are displayed in apps (docs say max of 20) | ||
| var rgbs = _customEffect.Frames.SelectMany(f => f.PanelColors.Values).Distinct().Take(20); | ||
| foreach(var rgb in rgbs) | ||
| { | ||
| customEffectCommand.Palette.Add(ColorFormatConverter.ToPalette(rgb)); | ||
| } | ||
| } | ||
|
|
||
| private string BuildPanelAnimData(int panelId) | ||
| { | ||
| //Example taken from docs. This method returns one of the panel rows | ||
| //(semicolons and newlines added for clarity only): | ||
| //numPanels; | ||
| //panelId0; numFrames0; RGBWT01; RGBWT02; ... RGBWT0n(0); | ||
| //panelId1; numFrames1; RGBWT11; RGBWT12; ... RGBWT1n(1); ... ... | ||
| //panelIdN; numFramesN; RGBWTN1; RGBWTN2; ... RGBWTNn(N); | ||
| //RGB=color, W=0, Txx is transition time is tenths of a second | ||
|
|
||
| var sb = new StringBuilder(); | ||
| uint? prevRgb = null; | ||
|
|
||
| var totalFrames = 0; | ||
| var sameColorFrameCount = 0; | ||
|
|
||
| foreach (var rgb in _customEffect.Frames.Select(f => f.PanelColors[panelId])) | ||
| { | ||
| if (prevRgb == null || rgb != prevRgb.Value) | ||
| { | ||
| if (prevRgb != null && sameColorFrameCount > 0) | ||
| { | ||
| sb.AppendFormat(" {0} {1} {2} 0 {3}", | ||
| (prevRgb >> 16) & 255, // Get the value for red by shifting 2 bytes right | ||
| (prevRgb >> 8) & 255, // Get the value for green by shifting one byte right | ||
| prevRgb & 255, // Get the value for blue by taking the lowest byte | ||
| sameColorFrameCount * _transitionTime); | ||
|
|
||
| totalFrames++; | ||
| } | ||
|
|
||
| sb.AppendFormat(" {0} {1} {2} 0 {3}", | ||
| (rgb >> 16) & 255, | ||
| (rgb >> 8) & 255, | ||
| rgb & 255, | ||
| _transitionTime); | ||
|
|
||
| sameColorFrameCount = 0; | ||
| totalFrames++; | ||
| } | ||
| else | ||
| { | ||
| sameColorFrameCount++; | ||
| } | ||
|
|
||
| prevRgb = rgb; | ||
| } | ||
|
|
||
| //Prepend panelId numframes | ||
| return string.Format(" {0} {1}{2}", panelId, totalFrames, sb); | ||
| } | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally prefer using either
IEnumerable<T>or justList<T>, don't see a point in usingIList<T>There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So IMHO IList
<T>is preferable toList<T>so we're not forcing the specific implementation ofList.IEnumerablemay be okay if I'm not using anyIListmethods. Sometimes you can end up with LINQ having to provide functionality that is already there, an example isCount.IListprovides a property forCount,IEnumerabledoesn't, so if you need to count the items you have to get LINQ to iterate over theIEnumerablefor you usingCount()rather than just using theCountproperty that would be there if it were anIList.The same is true for
Any(), rather thanCount > 0. This isn't as bad asCount()asAny()just needs to read one item from theIEnumerable, but it is still less efficient than theCountproperty.I'll see what I break if I change to
IEnumerableand get back to you.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of use of indexing, so it has to be
ListorIList. Personally I preferIListas this means if we ever wanted to swap the implementation fromListto a similar collection that still implementsIListwe would know it would definitely not break any existing code.