From 8e1405131faf58d39549cdb578ad79a9413b4c45 Mon Sep 17 00:00:00 2001 From: Misha Date: Wed, 6 Sep 2023 16:38:13 -0400 Subject: [PATCH 1/6] Implement AMAP format --- libmsstyle/Animation.cs | 584 ++++++++++++++++++ libmsstyle/CubicBezierTimingFunction.cs | 38 ++ libmsstyle/TimingFunction.cs | 81 +++ libmsstyle/Transform.cs | 140 +++++ libmsstyle/Transform2D.cs | 48 ++ libmsstyle/Transform3D.cs | 56 ++ libmsstyle/TransformOpacity.cs | 36 ++ libmsstyle/VisualStyle.cs | 148 ++++- libmsstyle/libmsstyle.csproj | 10 +- libmsstyleTests/libmsstyleTests.csproj | 3 +- msstyleEditorSharp/App.config | 6 +- msstyleEditorSharp/Dialogs/ClassView.cs | 93 ++- msstyleEditorSharp/Dialogs/MainWindow.cs | 83 ++- msstyleEditorSharp/Dialogs/PropertyView.cs | 35 ++ .../PropView/AnimationWrapper.cs | 123 ++++ .../PropView/EnumFlagCheckedListBox.cs | 231 +++++++ .../PropView/EnumFlagUIEditor.cs | 49 ++ msstyleEditorSharp/msstyleEditorSharp.csproj | 8 +- msstyleEditorSharp/packages.config | 2 +- 19 files changed, 1700 insertions(+), 74 deletions(-) create mode 100644 libmsstyle/Animation.cs create mode 100644 libmsstyle/CubicBezierTimingFunction.cs create mode 100644 libmsstyle/TimingFunction.cs create mode 100644 libmsstyle/Transform.cs create mode 100644 libmsstyle/Transform2D.cs create mode 100644 libmsstyle/Transform3D.cs create mode 100644 libmsstyle/TransformOpacity.cs create mode 100644 msstyleEditorSharp/PropView/AnimationWrapper.cs create mode 100644 msstyleEditorSharp/PropView/EnumFlagCheckedListBox.cs create mode 100644 msstyleEditorSharp/PropView/EnumFlagUIEditor.cs diff --git a/libmsstyle/Animation.cs b/libmsstyle/Animation.cs new file mode 100644 index 0000000..7c50b58 --- /dev/null +++ b/libmsstyle/Animation.cs @@ -0,0 +1,584 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class Animation + { + public int SizeInBytes; + public int PropertiesIndex; + public int TransformsIndex; + + public AnimationFlags AnimationFlags { get; set; } + public int TransformCount { get; set; } + public int StaggerDelay { get; set; } + public int StaggerDelayCap { get; set; } + public float StaggerDelayFactor { get; set; } + public int ZOrder { get; set; } + public int BackgroundPartID { get; set; } + public int TuningLevel { get; set; } + public float Perspective { get; set; } + private List _transforms = new List(); + public List Transforms { get { return _transforms; } } + public PropertyHeader Header; + public static Dictionary AnimationNameMap = new Dictionary() + { + { 1, new AnimationStates("Expand", new Dictionary + { + { 1, "Affected" }, + { 2, "Revealed" } + }) + }, + { 2, new AnimationStates("Collapse", new Dictionary + { + { 1, "Hidden" }, + { 2, "Affected" } + }) + }, + { 3, new AnimationStates("Reposition",new Dictionary()) }, + { 4, new AnimationStates("FadeIn", new Dictionary + { + { 1, "Shown" } + }) + }, + { 5, new AnimationStates("FadeOut", new Dictionary + { + { 1, "Hidden" } + }) + }, + { 6, new AnimationStates("AddToList", new Dictionary + { + { 1, "Added" }, + { 2, "Affected" } + }) + }, + { 7, new AnimationStates("DeleteFromList", new Dictionary + { + { 1, "Deleted" }, + { 2, "Remaining" } + }) + }, + { 8, new AnimationStates("AddToGrid", new Dictionary + { + { 1, "Added" }, + { 2, "Affected" }, + { 3, "RowOut" }, + { 4, "RowIn" } + }) + }, + { 9, new AnimationStates("DeleteFromGrid", new Dictionary + { + { 1, "Deleted" }, + { 2, "Remaining" }, + { 3, "RowOut" }, + { 4, "RowIn" } + }) + }, + { 10, new AnimationStates("AddToSearchGrid", new Dictionary + { + { 1, "Added" }, + { 2, "Affected" }, + { 3, "RowOut" }, + { 4, "RowIn" } + }) + }, + { 11, new AnimationStates("DeleteFromSearchGrid", new Dictionary + { + { 1, "Deleted" }, + { 2, "Remaining" }, + { 3, "RowOut" }, + { 4, "RowIn" } + }) + }, + { 12, new AnimationStates("AddToSearchList", new Dictionary + { + { 1, "Added" }, + { 2, "Affected" } + }) + }, + { 13, new AnimationStates("DeleteFromSearchList", new Dictionary + { + { 1, "Deleted" }, + { 2, "Remaining" } + }) + }, + { 14, new AnimationStates("ShowEdgeUI",new Dictionary(){ { 1, "Target" }, }) }, + { 15, new AnimationStates("ShowPanel",new Dictionary(){ { 1, "Target" }, }) }, + { 16, new AnimationStates("HideEdgeUI",new Dictionary(){ { 1, "Target" }, }) }, + { 17, new AnimationStates("HidePanel",new Dictionary(){ { 1, "Target" }, }) }, + { 18, new AnimationStates("ShowPopup",new Dictionary(){ { 1, "Target" }, }) }, + { 19, new AnimationStates("HidePopup",new Dictionary(){ { 1, "Target" }, }) }, + { 20, new AnimationStates("PointerDown",new Dictionary(){ { 1, "Target" }, }) }, + { 21, new AnimationStates("PointerUp",new Dictionary() { { 1, "Target" }, }) }, + { 22, new AnimationStates("DragSourceStart", new Dictionary + { + { 1, "DragSource" }, + { 2, "Affected" } + }) + }, + { 23, new AnimationStates("DragSourceEnd", new Dictionary + { + { 1, "DragSource" }, + { 2, "Affected" } + }) + }, + { 24, new AnimationStates("TransitionContent", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 25, new AnimationStates("Reveal", new Dictionary + { + { 1, "Background" }, + { 2, "Content" }, + { 3, "Outline" }, + { 4, "Tapped" } + }) + }, + { 26, new AnimationStates("Hide", new Dictionary + { + { 1, "Background" }, + { 2, "Content" }, + { 3, "Outline" }, + { 4, "Tapped" } + }) + }, + { 27, new AnimationStates("DragBetweenEnter", new Dictionary + { + { 1, "Affected" } + }) + }, + { 28, new AnimationStates("DragBetweenLeave", new Dictionary + { + { 1, "Affected" } + }) + }, + { 29, new AnimationStates("SwipeSelect", new Dictionary + { + { 1, "Selected" }, + { 2, "Selection" } + }) + }, + { 30, new AnimationStates("SwipeDeselect", new Dictionary + { + { 1, "Deselected" }, + { 2, "Selection" } + }) + }, + { 31, new AnimationStates("SwipeReveal",new Dictionary()) }, + { 32, new AnimationStates("EnterPage",new Dictionary()) }, + { 33, new AnimationStates("TransitionPage", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 34, new AnimationStates("CrossFade", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 35, new AnimationStates("Peek",new Dictionary()) }, + { 36, new AnimationStates("UpdateBadge", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 49, new AnimationStates("WindowOpen",new Dictionary() + { + { 1, "Target" }, + }) }, + { 50, new AnimationStates("WindowClose",new Dictionary() { + { 1, "Target" }, + }) }, + { 51, new AnimationStates("WindowMinimize",new Dictionary() { + { 1, "Target" }, + }) }, + { 52, new AnimationStates("WindowMaximize",new Dictionary() { { 1, "Target" }, }) }, + { 53, new AnimationStates("WindowRestoreFromMinimized", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" }, + { 7, "UnknownState(7)" }, + { 8, "UnknownState(8)" }, + { 9, "UnknownState(9)" }, + { 10, "UnknownState(10)" } + }) + }, + { 54, new AnimationStates("WindowRestoreFromMaximized", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" } + }) + }, + { 55, new AnimationStates("Login", new Dictionary + { + { 1, "LoginImage" }, + { 2, "LoginText" }, + { 3, "LauncherTiles" }, + { 4, "LauncherTileColumns" }, + { 5, "LauncherIcon" }, + { 6, "LauncherIconText" } + }) + }, + { 56, new AnimationStates("LauncherLaunch", new Dictionary + { + { 1, "Desktop" }, + { 2, "Launcher" }, + { 3, "LauncherTiles" }, + { 4, "LauncherText" }, + { 5, "LauncherIcon" }, + { 6, "LauncherSubheaders" }, + { 7, "Flyout" }, + { 8, "FullscreenFlyout" }, + { 9, "JumpList" } + }) + }, + { 57, new AnimationStates("LauncherDismiss", new Dictionary + { + { 1, "Desktop" }, + { 2, "Launcher" }, + { 3, "LauncherTiles" }, + { 4, "LauncherText" }, + { 5, "LauncherIcon" }, + { 6, "Timer" }, + { 7, "Flyout" } + }) + }, + { 58, new AnimationStates("AppLaunch", new Dictionary + { + { 1, "Activated" }, + { 2, "Remaining" } + }) + }, + { 59, new AnimationStates("AppSwitch", new Dictionary + { + { 1, "PageOut" } + }) + }, + { 60, new AnimationStates("TapDown3D", new Dictionary()) }, + { 61, new AnimationStates("TapUp3D", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" }, + { 7, "UnknownState(7)" } + }) + }, + { 62, new AnimationStates("Thumbnail", new Dictionary + { + { 1, "Animate" }, + { 2, "AnimateBounce" } + }) + }, + { 63, new AnimationStates("Resize", new Dictionary + { + { 1, "Before" } + }) + }, + { 64, new AnimationStates("NoAnimation", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" } + }) + }, + { 65, new AnimationStates("Unlock", new Dictionary + { + { 1, "Incoming" } + }) + }, + { 66, new AnimationStates("Tdbn", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" }, + { 7, "UnknownState(7)" }, + { 8, "UnknownState(8)" }, + { 9, "UnknownState(9)" }, + { 10, "UnknownState(10)" }, + { 11, "UnknownState(11)" }, + { 12, "UnknownState(12)" }, + { 13, "UnknownState(13)" } + }) + }, + { 67, new AnimationStates("AppArrangementImmediate", new Dictionary + { + { 1, "AppOut" }, + { 2, "Thumbnail" }, + { 3, "Static" }, + { 4, "Slide" }, + { 5, "SlideToPlace" }, + { 6, "AppClosed" }, + { 7, "AppOutMaximize" }, + { 8, "ReplaceFromTilt" }, + { 9, "ReplaceNoTilt" } + }) + }, + { 69, new AnimationStates("AppLaunchSwitch", new Dictionary + { + { 1, "UnknownState(1)" }, + { 2, "UnknownState(2)" } + }) + }, + { 70, new AnimationStates("ChangePanel", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 71, new AnimationStates("GrowPanel", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 72, new AnimationStates("ShrinkPanel", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" } + }) + }, + { 73, new AnimationStates("TileNotification", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" }, + { 3, "IncomingBranding" }, + { 4, "OutgoingBranding" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" } + }) + }, + { 74, new AnimationStates("ImmersiveBackground", new Dictionary + { + { 1, "FadeInBackground" }, + { 2, "FadeInAccent" }, + { 3, "FadeOutAccent" }, + { 4, "FadeInAccentLauncherLaunch" }, + { 5, "FadeInTranslateAccent" }, + { 6, "DelayedHideAccent" } + }) + }, + { 75, new AnimationStates("SSCrossfade", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" } + }) + }, + { 76, new AnimationStates("ScreenRotation", new Dictionary + { + { 1, "Before" }, + { 2, "BeforeOutgoing" }, + { 3, "After" } + }) + }, + { 77, new AnimationStates("InplaceResize", new Dictionary + { + { 1, "AnchorTop" }, + { 2, "AnchorBottom" }, + { 3, "AnchorRight" }, + { 4, "AnchorLeft" } + }) + }, + { 78, new AnimationStates("DialogSwitch", new Dictionary(){ { 1, "Target" }, }) }, + { 79, new AnimationStates("LogonEnterPage", new Dictionary(){ { 1, "Target" }, }) }, + { 80, new AnimationStates("CrossfadeInPlace", new Dictionary + { + { 1, "Incoming" }, + { 2, "Outgoing" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" }, + { 6, "UnknownState(6)" }, + { 7, "UnknownState(7)" } + }) + }, + { 81, new AnimationStates("ScreenshotFadeOut", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" } + }) + }, + { 82, new AnimationStates("ShowCharm",new Dictionary(){ { 1, "Target" }, }) }, + { 83, new AnimationStates("HideCharm",new Dictionary(){ { 1, "Target" }, }) }, + { 84, new AnimationStates("FadeInLong", new Dictionary + { + { 1, "Shown" } + }) + }, + { 85, new AnimationStates("FadeOutLong", new Dictionary + { + { 1, "Hidden" } + }) + }, + { 86, new AnimationStates("AddToGridStaggered", new Dictionary + { + { 1, "Added" } + }) + }, + { 87, new AnimationStates("DeleteFromGridStaggered", new Dictionary + { + { 1, "Deleted" } + }) + }, + { 88, new AnimationStates("DragSourceStartMulti", new Dictionary + { + { 1, "DragSource" }, + { 2, "Affected" }, + { 3, "Content" }, + { 4, "Adornment" } + }) + }, + { 89, new AnimationStates("DragSourceEndMulti", new Dictionary + { + { 1, "DragSource" }, + { 2, "Affected" }, + { 3, "Content" }, + { 4, "Adornment" } + }) + }, + { 90, new AnimationStates("VirtualDesktopSwitch", new Dictionary + { + { 1, "Target" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" }, + { 5, "UnknownState(5)" } + }) + }, + { 91, new AnimationStates("TabletModeTransition", new Dictionary + { + { 1, "DesktopBefore" }, + { 2, "UnknownState(2)" }, + { 3, "UnknownState(3)" }, + { 4, "UnknownState(4)" } + }) + } + }; + public Animation(byte[] data, ref int start, PropertyHeader header) + { + this.Header = header; + SizeInBytes = BitConverter.ToInt32(data, start + 0); //copy of sizeInBytes of the VS record + PropertiesIndex = BitConverter.ToInt32(data, start + 4); + TransformsIndex = BitConverter.ToInt32(data, start + 8); + start += 16; //skip past padding + + //Read properties structure + AnimationFlags = (AnimationFlags)BitConverter.ToInt32(data, start + 0); + TransformCount = BitConverter.ToInt32(data, start + 4); + StaggerDelay = BitConverter.ToInt32(data, start + 8); + StaggerDelayCap = BitConverter.ToInt32(data, start + 12); + StaggerDelayFactor = BitConverter.ToSingle(data, start + 16); + ZOrder = BitConverter.ToInt32(data, start + 20); + BackgroundPartID = BitConverter.ToInt32(data, start + 24); + TuningLevel = BitConverter.ToInt32(data, start + 28); + Perspective = BitConverter.ToSingle(data, start + 32); + + start += 40; //skip past padding + + for (int i = 0; i < TransformCount; i++) + { + var t = new Transform(data, ref start); + Transforms.Add(t); + start += GetPaddingForSize(t.StructureSize); + } + + + } + + int GetPaddingForSize(int size) + { + const int sizeOfRecordHeader = 32; + return ((size + 39) & -8) - sizeOfRecordHeader - size; + } + + public void Write(BinaryWriter bw) + { + //Update the total size + int total_size = 56; + foreach (var item in Transforms) + { + total_size += item.StructureSize + GetPaddingForSize(item.StructureSize); + } + + Header.sizeInBytes = total_size; + + bw.Write(Header.Serialize()); + WriteData(bw); + } + public void WriteData(BinaryWriter bw) + { + TransformCount = Transforms.Count; + + //write animation header + bw.Write(Header.sizeInBytes); + bw.Write(16); //Property index (always seems to be the same) + bw.Write(56); + bw.Write(0); + + //write animation structure + bw.Write((int)AnimationFlags); + bw.Write(Transforms.Count); + bw.Write(StaggerDelay); + bw.Write(StaggerDelayCap); + bw.Write(StaggerDelayFactor); + bw.Write(ZOrder); + bw.Write(BackgroundPartID); + bw.Write(TuningLevel); + bw.Write(Perspective); + bw.Write(0); //Write padding + + foreach (var item in Transforms) + { + item.Write(bw); + + //write padding + var padding = new byte[GetPaddingForSize(item.StructureSize)]; + bw.Write(padding); + } + } + } + [Flags] + public enum AnimationFlags + { + None = 0, + HasStagger = 1, + IsRtlAware = 2, + HasBackground = 3, + HasPerspective = 4 + } + + public class AnimationStates + { + public string AnimationName; + public Dictionary AnimationStateDict; + public AnimationStates(string name, Dictionary states) + { + AnimationName = name; + AnimationStateDict = states; + } + } +} diff --git a/libmsstyle/CubicBezierTimingFunction.cs b/libmsstyle/CubicBezierTimingFunction.cs new file mode 100644 index 0000000..6612c24 --- /dev/null +++ b/libmsstyle/CubicBezierTimingFunction.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class CubicBezierTimingFunction + { + public float RX0 { get; set; } + public float RY0 { get; set; } + + public float RX1 { get; set; } + public float RY1 { get; set; } + + public CubicBezierTimingFunction(byte[] data, int start) + { + RX0 = BitConverter.ToSingle(data, start + 0); + RY0 = BitConverter.ToSingle(data, start + 4); + RX1 = BitConverter.ToSingle(data, start + 8); + RY1 = BitConverter.ToSingle(data, start + 12); + } + + internal void Write(BinaryWriter w) + { + w.Write(RX0); + w.Write(RY0); + w.Write(RX1); + w.Write(RY1); + } + public override string ToString() + { + return "Cubic Bezier function"; + } + } +} diff --git a/libmsstyle/TimingFunction.cs b/libmsstyle/TimingFunction.cs new file mode 100644 index 0000000..42d060c --- /dev/null +++ b/libmsstyle/TimingFunction.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + //[Serializable] + public class TimingFunction + { + public TimingFunctionType Type { get; set; } + [TypeConverter(typeof(ExpandableObjectConverter))] + public CubicBezierTimingFunction CubicBezier { get; set; } + + public PropertyHeader Header; + public static Dictionary TimingFunctionNameMap = new Dictionary() + { + {1 , "Linear"}, + {2 , "EaseIn"}, + {3 , "EaseOut"}, +{4 , "FastIn"}, +{5 , "Exponential"}, +{6 , "FastInFortySevenPercent"}, +{49 , "ExponetialReversed"}, +{50 , "DmBoundary"}, +{51 , "DmSnAppoint"}, +{52 , "LogInPathX"}, +{53 , "LogInPathY"}, +{54 , "LogInPathZ"}, +{58 , "CustomFlipping"}, +{59 , "AppLaunchScale"}, +{60 , "AppLaunchDrift"}, +{61 , "AppLaunchFastIn"}, +{62 , "FastInTenPercent"}, +{63 , "AppLaunchRotateBounce"}, +{64 , "AppLaunchRotateBounceDelayed"}, +{65 , "DesktopWithPop"}, + }; + public TimingFunction(byte[] data, int start, PropertyHeader header) + { + this.Header = header; + Type = (TimingFunctionType)BitConverter.ToInt32(data, start + 0); + start += 4; + if (Type == TimingFunctionType.CubicBezier) + { + //Cubic Bezier function + CubicBezier = new CubicBezierTimingFunction(data, start); + } + else + { + throw new Exception("Unknown timing function type: " + Type); + } + } + public void Write(BinaryWriter bw) + { + bw.Write(Header.Serialize()); + WriteData(bw); + } + public void WriteData(BinaryWriter w) + { + w.Write((int)Type); + if(Type == TimingFunctionType.CubicBezier) + { + CubicBezier.Write(w); + } + w.Write(0); //Write padding + } + public override string ToString() + { + return "Timing function"; + } + } + public enum TimingFunctionType : uint + { + Undefined = 0, + CubicBezier = 1, + } +} diff --git a/libmsstyle/Transform.cs b/libmsstyle/Transform.cs new file mode 100644 index 0000000..c19a5a7 --- /dev/null +++ b/libmsstyle/Transform.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class Transform + { + public TransformType Type { get; set; } + public int TimingFunctionID { get; set; } + public int StartTime { get; set; } + public int DurationTime { get; set; } + public TransformFlag Flags { get; set; } + [TypeConverter(typeof(ExpandableObjectConverter))] + + public Transform3D Transform3DStructure { get; set; } + [TypeConverter(typeof(ExpandableObjectConverter))] + + public Transform2D Transform2DStructure { get; set; } + [TypeConverter(typeof(ExpandableObjectConverter))] + + public TransformOpacity TransformOpacity { get; set; } + + public int StructureSize + { + get + { + int header = 20; //header + + if (Type == TransformType.Roatate3D || Type == TransformType.Scale3D || Type == TransformType.Translate3d) + { + header += 36; + } + else if (Type == TransformType.Translate2D || Type == TransformType.Scale2D) + { + header += 24; + } + else if (Type == TransformType.Opacity) + { + header += 8; + } + else + { + throw new NotImplementedException("Unknown transform type: " + Type); + } + + return header; + } + } + public Transform() + { + Transform3DStructure = new Transform3D(); + Transform2DStructure = new Transform2D(); + TransformOpacity = new TransformOpacity(); + } + public Transform(byte[] data, ref int start) + { + Type = (TransformType)BitConverter.ToInt32(data, start + 0); + TimingFunctionID = BitConverter.ToInt32(data, start + 4); + StartTime = BitConverter.ToInt32(data, start + 8); + DurationTime = BitConverter.ToInt32(data, start + 12); + Flags = (TransformFlag)BitConverter.ToInt32(data, start + 16); + start += 20; + if (Type == TransformType.Roatate3D || Type == TransformType.Scale3D || Type == TransformType.Translate3d) + { + Transform3DStructure = new Transform3D(data, start); + start += 36; + } + else if (Type == TransformType.Translate2D || Type == TransformType.Scale2D) + { + Transform2DStructure = new Transform2D(data, start); + start += 24; + } + else if (Type == TransformType.Opacity) + { + TransformOpacity = new TransformOpacity(data, start); + start += 8; + } + else + { + throw new NotImplementedException("Unknown transform type: " + Type); + } + } + + public void Write(BinaryWriter bw) + { + bw.Write((int)Type); + bw.Write(TimingFunctionID); + bw.Write(StartTime); + bw.Write(DurationTime); + bw.Write((int)Flags); + + if (Type == TransformType.Roatate3D || Type == TransformType.Scale3D || Type == TransformType.Translate3d) + { + Transform3DStructure.Write(bw); + } + else if (Type == TransformType.Translate2D || Type == TransformType.Scale2D) + { + Transform2DStructure.Write(bw); + } + else if (Type == TransformType.Opacity) + { + TransformOpacity.Write(bw); + } + else + { + throw new NotImplementedException("Unknown transform type: " + Type); + } + } + + public override string ToString() + { + return "Transform"; + } + } + + public enum TransformType + { + Translate2D = 0, + Scale2D = 1, + Opacity = 2, + Clip = 3, + Translate3d = 258, + Scale3D = 259, + Roatate3D = 260, + } + [Flags] + public enum TransformFlag + { + None = 0, + TargetValuesUser = 1, + HasInitialValues = 2, + HasOrginValues = 4 + } +} diff --git a/libmsstyle/Transform2D.cs b/libmsstyle/Transform2D.cs new file mode 100644 index 0000000..5ad73ea --- /dev/null +++ b/libmsstyle/Transform2D.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class Transform2D + { + public float rX { get; set; } + public float rY { get; set; } + public float rInitialX { get; set; } + public float rInitialY { get; set; } + public float rOriginX { get; set; } + public float rOriginY { get; set; } + + public Transform2D(byte[] data, int start) + { + rX = BitConverter.ToSingle(data, start + 0); + rY = BitConverter.ToSingle(data, start + 4); + rInitialX = BitConverter.ToSingle(data, start + 8); + rInitialY = BitConverter.ToSingle(data, start + 12); + rOriginX = BitConverter.ToSingle(data, start + 16); + rOriginY = BitConverter.ToSingle(data, start + 20); + } + + public Transform2D() + { + + } + + public void Write(BinaryWriter bw) + { + bw.Write(rX); + bw.Write(rY); + bw.Write(rInitialX); + bw.Write(rInitialY); + bw.Write(rOriginX); + bw.Write(rOriginY); + } + public override string ToString() + { + return "2D Transform"; + } + } +} diff --git a/libmsstyle/Transform3D.cs b/libmsstyle/Transform3D.cs new file mode 100644 index 0000000..5e86ef0 --- /dev/null +++ b/libmsstyle/Transform3D.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class Transform3D + { + public float rX { get; set; } + public float rY { get; set; } + public float rZ { get; set; } + public float rInitialX { get; set; } + public float rInitialY { get; set; } + public float rInitialZ { get; set; } + public float rOriginX { get; set; } + public float rOriginY { get; set; } + public float rOriginZ { get; set; } + public Transform3D() + { + + } + + public Transform3D(byte[] data, int start) + { + rX = BitConverter.ToSingle(data, start + 0); + rY = BitConverter.ToSingle(data, start + 4); + rZ = BitConverter.ToSingle(data, start + 8); + rInitialX = BitConverter.ToSingle(data, start + 12); + rInitialY = BitConverter.ToSingle(data, start + 16); + rInitialZ = BitConverter.ToSingle(data, start + 20); + rOriginX = BitConverter.ToSingle(data, start + 24); + rOriginY = BitConverter.ToSingle(data, start + 28); + rOriginZ = BitConverter.ToSingle(data, start + 32); + } + + public void Write(BinaryWriter bw) + { + bw.Write(rX); + bw.Write(rY); + bw.Write(rZ); + bw.Write(rInitialX); + bw.Write(rInitialY); + bw.Write(rInitialZ); + bw.Write(rOriginX); + bw.Write(rOriginY); + bw.Write(rOriginZ); + } + public override string ToString() + { + return "3D Transform"; + } + } +} diff --git a/libmsstyle/TransformOpacity.cs b/libmsstyle/TransformOpacity.cs new file mode 100644 index 0000000..18f4dca --- /dev/null +++ b/libmsstyle/TransformOpacity.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace libmsstyle +{ + public class TransformOpacity + { + public float Opacity { get; set; } + public float InitialOpacity { get; set; } + + public TransformOpacity(byte[] data, int start) + { + Opacity = BitConverter.ToSingle(data, start + 0); + InitialOpacity = BitConverter.ToSingle(data, start + 4); + } + + public TransformOpacity() + { + + } + + public void Write(BinaryWriter wr) + { + wr.Write(Opacity); + wr.Write(InitialOpacity); + } + public override string ToString() + { + return "Opacity Transform"; + } + } +} diff --git a/libmsstyle/VisualStyle.cs b/libmsstyle/VisualStyle.cs index f6b86ec..19cb06f 100644 --- a/libmsstyle/VisualStyle.cs +++ b/libmsstyle/VisualStyle.cs @@ -1,8 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; @@ -26,10 +28,22 @@ public Platform Platform private Dictionary m_classes; public Dictionary Classes - { + { get { return m_classes; } } + private List m_timingFunctions; + public List TimingFunctions + { + get { return m_timingFunctions; } + } + + private List m_animations; + public List Animations + { + get { return m_animations; } + } + private int m_numProps; public int NumProperties { @@ -59,6 +73,8 @@ public VisualStyle() m_classes = new Dictionary(); m_stringTable = new Dictionary(); m_resourceUpdates = new Dictionary(); + m_timingFunctions = new List(); + m_animations = new List(); m_numProps = 0; m_resourceLanguage = 0; } @@ -100,21 +116,29 @@ public void Save(string file, bool makeStandalone = false) else throw new ArgumentException("Cannot overwrite the original file!"); var updateHandle = Win32Api.BeginUpdateResource(file, false); - if(updateHandle == IntPtr.Zero) + if (updateHandle == IntPtr.Zero) { File.Delete(file); throw new IOException("Could not open the file for writing! (BeginUpdateResource)"); } var moduleHandle = Win32Api.LoadLibraryEx(file, IntPtr.Zero, Win32Api.LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); - if(moduleHandle == IntPtr.Zero) + if (moduleHandle == IntPtr.Zero) { Win32Api.EndUpdateResource(updateHandle, true); File.Delete(file); throw new IOException("Could not open the file for writing! (LoadLibraryEx)"); } - if(!SaveResources(moduleHandle, updateHandle)) + if (!SaveResources(moduleHandle, updateHandle)) + { + Win32Api.FreeLibrary(moduleHandle); + Win32Api.EndUpdateResource(updateHandle, true); + File.Delete(file); + throw new IOException("Could not save resources!"); + } + + if (!SaveAMap(moduleHandle, updateHandle)) { Win32Api.FreeLibrary(moduleHandle); Win32Api.EndUpdateResource(updateHandle, true); @@ -145,7 +169,7 @@ public void Save(string file, bool makeStandalone = false) // close the module before calling EndUpdate(). If not // updating fails because the file is in use. Win32Api.FreeLibrary(moduleHandle); - if(!Win32Api.EndUpdateResource(updateHandle, false)) + if (!Win32Api.EndUpdateResource(updateHandle, false)) { File.Delete(file); throw new IOException("Could not write the changes to the file!"); @@ -170,14 +194,14 @@ public void Save(string file, bool makeStandalone = false) private bool SaveResources(IntPtr moduleHandle, IntPtr updateHandle) { - foreach(var res in m_resourceUpdates) + foreach (var res in m_resourceUpdates) { byte[] data = null; try { data = File.ReadAllBytes(res.Value); } - catch(Exception) + catch (Exception) { return false; } @@ -194,7 +218,7 @@ private bool SaveResources(IntPtr moduleHandle, IntPtr updateHandle) } ushort lid = ResourceAccess.GetFirstLanguageId(moduleHandle, type, (uint)res.Key.ResourceId); - if(lid == 0xFFFF) + if (lid == 0xFFFF) { lid = m_resourceLanguage; } @@ -213,19 +237,19 @@ private bool SaveProperties(IntPtr moduleHandle, IntPtr updateHandle) MemoryStream ms = new MemoryStream(4096); BinaryWriter bw = new BinaryWriter(ms); - foreach(var cls in m_classes) + foreach (var cls in m_classes) { - foreach(var part in cls.Value.Parts) + foreach (var part in cls.Value.Parts) { - foreach(var state in part.Value.States) + foreach (var state in part.Value.States) { state.Value.Properties.Sort(Comparer.Create( - (p1, p2) => + (p1, p2) => { return p1.Header.nameID.CompareTo(p2.Header.nameID); })); - foreach(var prop in state.Value.Properties) + foreach (var prop in state.Value.Properties) { PropertyStream.WriteProperty(bw, prop); } @@ -241,12 +265,12 @@ private bool SaveProperties(IntPtr moduleHandle, IntPtr updateHandle) private void SaveStringTable(IntPtr moduleHandle, IntPtr updateHandle, bool makeStandalone) { - if(m_stringTable.Count == 0) + if (m_stringTable.Count == 0) { return; } - if(makeStandalone) + if (makeStandalone) { // To make a .msstyle relocatable, we need to remove the MUI (Multilingual UI) resource // entries and store the string table that was in the .mui's in the .msstyle itself. @@ -266,7 +290,7 @@ private void SaveStringTable(IntPtr moduleHandle, IntPtr updateHandle, bool make // - If we attempt to delete via LANG_NEUTRAL we get ERROR_INVALID_PARAMETER. ushort langId = ResourceAccess.GetFirstLanguageId(moduleHandle, "MUI", 1); - if(langId != 0xFFFF) + if (langId != 0xFFFF) { if (!Win32Api.UpdateResource(updateHandle, "MUI", 1, langId, null, 0)) { @@ -288,6 +312,32 @@ private void SaveStringTable(IntPtr moduleHandle, IntPtr updateHandle, bool make } } + private bool SaveAMap(IntPtr moduleHandle, IntPtr updateHandle) + { + if (m_animations.Count == 0 && m_timingFunctions.Count == 0) + return true; + + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + + foreach (var item in m_timingFunctions) + { + item.Write(bw); + } + foreach (var item in m_animations) + { + item.Write(bw); + } + + ushort lid = ResourceAccess.GetFirstLanguageId(moduleHandle, "AMAP", "AMAP"); + if (lid == 0xFFFF) + { + lid = m_resourceLanguage; + } + byte[] data = ms.ToArray(); + return Win32Api.UpdateResource(updateHandle, "AMAP", "AMAP", lid, data, (uint)data.Length); + + } public void Load(string file) { m_moduleHandle = Win32Api.LoadLibraryEx(file, IntPtr.Zero, Win32Api.LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); @@ -303,6 +353,15 @@ public void Load(string file) } LoadClassmap(cmap); + + byte[] amap = ResourceAccess.GetResource(m_moduleHandle, "AMAP", "AMAP"); + if (amap == null) + { + throw new Exception("Style contains no animation map!"); + } + + LoadAMap(amap); + m_platform = DeterminePlatform(); BuildPropertyTree(m_platform); @@ -341,7 +400,7 @@ public void Load(string file) // Get users preferred language for display purposes. // If we don't have it, choose any. int uiLang = System.Threading.Thread.CurrentThread.CurrentUICulture.LCID; - if(!m_stringTables.TryGetValue(uiLang, out m_stringTable)) + if (!m_stringTables.TryGetValue(uiLang, out m_stringTable)) { var kvp = m_stringTables.FirstOrDefault((t) => t.Value.Count > 0); m_stringTable = kvp.Value ?? new Dictionary(); @@ -380,7 +439,7 @@ void LoadProperties(byte[] pmap) { int cursor = 0; - while(cursor < pmap.Length - 4) + while (cursor < pmap.Length - 4) { try { @@ -389,13 +448,13 @@ void LoadProperties(byte[] pmap) //Debug.WriteLine("[N: {0}, T: {1}, C: {2}, P: {3}, S: {4}]", prop.Header.nameID, prop.Header.typeID, prop.Header.classID, prop.Header.partID, prop.Header.stateID); StyleClass cls; - if(!m_classes.TryGetValue(prop.Header.classID, out cls)) + if (!m_classes.TryGetValue(prop.Header.classID, out cls)) { throw new Exception("Found property with unknown class ID"); } StylePart part; - if(!cls.Parts.TryGetValue(prop.Header.partID, out part)) + if (!cls.Parts.TryGetValue(prop.Header.partID, out part)) { part = new StylePart() { @@ -421,13 +480,40 @@ void LoadProperties(byte[] pmap) state.Properties.Add(prop); ++m_numProps; } - catch(Exception) + catch (Exception) { } } } + void LoadAMap(byte[] amap) + { + int cursor = 0; + + while (cursor < amap.Length - 4) + { + PropertyHeader header = new PropertyHeader(amap, cursor); + + cursor += 32; + if (header.nameID == 20100) + { + //timing function + m_timingFunctions.Add(new TimingFunction(amap, cursor, header)); + cursor += 24; //The 4 bytes are added as there is a 4 byte padding + } + else if (header.nameID == 20000) + { + //animation + m_animations.Add(new Animation(amap, ref cursor, header)); + } + else + { + throw new Exception("unknown amap name ID"); + } + } + } + Platform DeterminePlatform() { bool foundDWMTouch = false; @@ -452,9 +538,9 @@ Platform DeterminePlatform() } if (cls.Value.ClassName == "QueryBuilder") { - foundVistaQueryBuilder = true; continue; + foundVistaQueryBuilder = true; continue; } - if(cls.Value.ClassName == "DarkMode::TaskManager") + if (cls.Value.ClassName == "DarkMode::TaskManager") { foundTaskBand2Light_Taskband2 = true; continue; } @@ -473,10 +559,10 @@ Platform DeterminePlatform() void BuildPropertyTree(Platform p) { - foreach(var cls in m_classes) + foreach (var cls in m_classes) { var partList = VisualStyleParts.Find(cls.Value.ClassName, p); - foreach(var partDescription in partList) + foreach (var partDescription in partList) { StylePart part = new StylePart() { @@ -485,7 +571,7 @@ void BuildPropertyTree(Platform p) }; cls.Value.Parts.Add(part.PartId, part); - foreach(var stateDescription in partDescription.States) + foreach (var stateDescription in partDescription.States) { StyleState state = new StyleState() { @@ -500,7 +586,7 @@ void BuildPropertyTree(Platform p) public StyleResource GetResourceFromProperty(StyleProperty prop) { - switch(prop.Header.typeID) + switch (prop.Header.typeID) { case (int)IDENTIFIER.FILENAME: case (int)IDENTIFIER.FILENAME_LITE: @@ -514,8 +600,8 @@ public StyleResource GetResourceFromProperty(StyleProperty prop) return new StyleResource(data, prop.Header.shortFlag, StyleResourceType.Atlas); } default: - { - return null; + { + return null; } } } @@ -533,9 +619,9 @@ public string GetQueuedResourceUpdate(int nameId, StyleResourceType type) public void QueueResourceUpdate(int nameId, StyleResourceType type, string pathToNew) - { + { var key = new StyleResource(null, nameId, type); m_resourceUpdates[key] = pathToNew; - } + } } } diff --git a/libmsstyle/libmsstyle.csproj b/libmsstyle/libmsstyle.csproj index 0d9437e..52bcce0 100644 --- a/libmsstyle/libmsstyle.csproj +++ b/libmsstyle/libmsstyle.csproj @@ -9,9 +9,10 @@ Properties libmsstyle libmsstyle - v4.5 + v4.6 512 true + true @@ -61,6 +62,8 @@ + + @@ -72,6 +75,11 @@ + + + + + diff --git a/libmsstyleTests/libmsstyleTests.csproj b/libmsstyleTests/libmsstyleTests.csproj index d60dcf5..c9dacc1 100644 --- a/libmsstyleTests/libmsstyleTests.csproj +++ b/libmsstyleTests/libmsstyleTests.csproj @@ -10,7 +10,7 @@ Properties libmsstyleTests libmsstyleTests - v4.5 + v4.6 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15.0 @@ -20,6 +20,7 @@ UnitTest + true diff --git a/msstyleEditorSharp/App.config b/msstyleEditorSharp/App.config index 8e15646..2d2a12d 100644 --- a/msstyleEditorSharp/App.config +++ b/msstyleEditorSharp/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/msstyleEditorSharp/Dialogs/ClassView.cs b/msstyleEditorSharp/Dialogs/ClassView.cs index b807492..844867f 100644 --- a/msstyleEditorSharp/Dialogs/ClassView.cs +++ b/msstyleEditorSharp/Dialogs/ClassView.cs @@ -38,14 +38,97 @@ public void SetVisualStyle(VisualStyle style) { var clsNode = new TreeNode(cls.Value.ClassName); clsNode.Tag = cls.Value; + if (cls.Value.ClassName == "timingfunction") + { + foreach (TimingFunction timingFunction in m_style.TimingFunctions) + { + string name; + if (TimingFunction.TimingFunctionNameMap.ContainsKey(timingFunction.Header.partID)) + { + name = TimingFunction.TimingFunctionNameMap[timingFunction.Header.partID]; + } + else + { + name = "Unknown part:" + timingFunction.Header.partID; + } + var partNode = new TreeNode(name); + partNode.Tag = timingFunction; + clsNode.Nodes.Add(partNode); + } + } + else if (cls.Value.ClassName == "animations") + { + //contains + Dictionary nodes = new Dictionary(); + foreach (Animation animation in m_style.Animations) + { + + TreeNode partNode; + bool exists = false; + if (nodes.ContainsKey(animation.Header.partID)) + { + exists = true; + partNode = nodes[animation.Header.partID]; + } + else + { + //check if the name is known + if (Animation.AnimationNameMap.ContainsKey(animation.Header.partID)) + { + partNode = new TreeNode(Animation.AnimationNameMap[animation.Header.partID].AnimationName); + } + else + { + partNode = new TreeNode("Unknown part " + animation.Header.partID); + } + } + + //Add the state - foreach (var part in cls.Value.Parts) + + string stateName; + + + if (Animation.AnimationNameMap.ContainsKey(animation.Header.partID)) + { + if(Animation.AnimationNameMap[animation.Header.partID].AnimationStateDict.ContainsKey(animation.Header.stateID)) + { + stateName = Animation.AnimationNameMap[animation.Header.partID].AnimationStateDict[animation.Header.stateID]; + } + else + { + stateName = "Unknown state: " + animation.Header.stateID; + } + } + else + { + stateName = "Unknown state: "+ animation.Header.stateID; + } + //add the state + var stateNode = new TreeNode(stateName); + stateNode.Tag = animation; + partNode.Nodes.Add(stateNode); + + //add the part node if it wasnt added + if (!exists) + { + nodes.Add(animation.Header.partID, partNode); + clsNode.Nodes.Add(partNode); + } + + } + } + else { - var partNode = new TreeNode(part.Value.PartName); - partNode.Tag = part.Value; + foreach (var part in cls.Value.Parts) + { + var partNode = new TreeNode(part.Value.PartName); + partNode.Tag = part.Value; - clsNode.Nodes.Add(partNode); + clsNode.Nodes.Add(partNode); + } } + classView.Nodes.Add(clsNode); } classView.Sort(); @@ -118,7 +201,7 @@ public void CollapseAll() private void OnTreeItemSelected(object sender, TreeViewEventArgs e) { - if(OnSelectionChanged != null) + if (OnSelectionChanged != null) { OnSelectionChanged(sender, e); } diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index f0613f5..28cc2ee 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -27,6 +27,8 @@ public partial class MainWindow : Form private ImageView m_imageView; private RenderView m_renderView; + private TimingFunction m_selectedTimingFunction; + private Animation m_selectedAnimation; public MainWindow() { InitializeComponent(); @@ -68,15 +70,15 @@ public MainWindow() m_propertyView.OnPropertyAdded += OnPropertyAdded; m_propertyView.OnPropertyRemoved += OnPropertyRemoved; - try + try { m_themeManager = new ThemeManager(); } - catch(Exception ex) + catch (Exception ex) { - MessageBox.Show(ex.Message + "\r\nIs Aero/DWM disabled? Starting without \"Test Theme\" feature.", - "Themeing API unavailable", - MessageBoxButtons.OK, + MessageBox.Show(ex.Message + "\r\nIs Aero/DWM disabled? Starting without \"Test Theme\" feature.", + "Themeing API unavailable", + MessageBoxButtons.OK, MessageBoxIcon.Warning); btTestTheme.Enabled = false; } @@ -129,7 +131,7 @@ private void UpdateStatusText(string text) private void UpdateImageInfo(Image img) { - if(img == null) + if (img == null) { lbImageInfo.Visible = false; } @@ -148,10 +150,10 @@ private void OpenStyle(string path) m_style.Load(path); UpdateWindowCaption(path); } - catch(Exception ex) + catch (Exception ex) { - MessageBox.Show(this, $"Are you sure this is a Windows Vista or higher visual style?\r\n\r\nDetails: {ex.Message}", "Error loading style!", - MessageBoxButtons.OK, + MessageBox.Show(this, $"Are you sure this is a Windows Vista or higher visual style?\r\n\r\nDetails: {ex.Message}", "Error loading style!", + MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -274,7 +276,7 @@ private StyleResource UpdateImageView(StyleProperty prop) if (prop == null) { btImageExport.Enabled = false; - btImageImport.Enabled = false; + btImageImport.Enabled = false; m_imageView.ViewImage = null; UpdateImageInfo(null); return null; @@ -294,7 +296,7 @@ private StyleResource UpdateImageView(StyleProperty prop) // see if there is a pending update to the resource string file = m_style.GetQueuedResourceUpdate(prop.Header.shortFlag, resType); - + // in any case, we have to store the update info of the real resource // we need that in order to export/replace? var resource = m_style.GetResourceFromProperty(prop); @@ -349,21 +351,21 @@ private void OnFileSaveClick(object sender, EventArgs e) OverwritePrompt = true }; - if(sfd.ShowDialog() != DialogResult.OK) + if (sfd.ShowDialog() != DialogResult.OK) { return; } try { - if(sender == btFileSave) + if (sender == btFileSave) m_style.Save(sfd.FileName, true); - else if(sender == btFileSaveWithMUI) + else if (sender == btFileSaveWithMUI) m_style.Save(sfd.FileName, false); lbStatusMessage.Text = "Style saved successfully!"; } - catch(Exception ex) + catch (Exception ex) { MessageBox.Show(ex.Message, "Error saving file!", MessageBoxButtons.OK, MessageBoxIcon.Error); } @@ -453,6 +455,25 @@ private void OnTreeItemSelected(object sender, TreeViewEventArgs e) DisplayPart(cls, part); return; } + + TimingFunction func = e.Node.Tag as TimingFunction; + if (func != null) + { + m_selectedTimingFunction = func; + m_propertyView.SetTimingFunction(func); + return; + } + + Animation animation = e.Node.Tag as Animation; + if (animation != null) + { + m_selectedAnimation = animation; + m_propertyView.SetAnimation(animation); + return; + } + + //nothing valid is selected, clear the property grid + m_propertyView.SetStylePart(null, null, null); } private void OnTreeKeyPress(object sender, KeyPressEventArgs e) @@ -485,7 +506,7 @@ private void OnToggleImageView(object sender, EventArgs e) private void OnTestTheme(object sender, EventArgs e) { - if(m_themeManager.IsThemeInUse) + if (m_themeManager.IsThemeInUse) { try { @@ -542,7 +563,7 @@ private void OnTestTheme(object sender, EventArgs e) needConfirmation = true; } - if(needConfirmation) + if (needConfirmation) { if (MessageBox.Show("It looks like the style was not made for this windows version. Try to apply it anyways?" , "msstyleEditor" @@ -601,13 +622,13 @@ private void OnImageViewBackgroundChanged(object sender, EventArgs e) private void OnImageExport(object sender, EventArgs e) { - if(m_selectedImage == null) + if (m_selectedImage == null) { MessageBox.Show("Select an image first!", "Export Image", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } - if(m_selectedImage.Data == null) + if (m_selectedImage.Data == null) { MessageBox.Show("This image resource doesn't exist yet!", "Export Image", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -619,8 +640,8 @@ private void OnImageExport(object sender, EventArgs e) m_selection.Class.ClassName, m_selection.Part.PartName, m_selectedImage.ResourceId.ToString()); - - foreach(var c in Path.GetInvalidFileNameChars()) + + foreach (var c in Path.GetInvalidFileNameChars()) { suggestedName = suggestedName.Replace(c, '-'); } @@ -640,7 +661,7 @@ private void OnImageExport(object sender, EventArgs e) fs.Write(m_selectedImage.Data, 0, m_selectedImage.Data.Length); } } - catch(Exception ex) + catch (Exception ex) { MessageBox.Show(ex.Message, "Error saving image!", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -652,7 +673,7 @@ private void OnImageExport(object sender, EventArgs e) private void OnImageImport(object sender, EventArgs e) { - if(m_selectedImage == null) + if (m_selectedImage == null) { MessageBox.Show("Select an image to replace first!", "Replace Image", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; @@ -668,7 +689,7 @@ private void OnImageImport(object sender, EventArgs e) } var res = ImageFormats.IsImageSupported(ofd.FileName); - if(!res.Item1) + if (!res.Item1) { MessageBox.Show("Bad image:\n" + res.Item2, "Replace Image", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -709,7 +730,7 @@ private void OnPropertyRemoved(StyleProperty prop) private void OnSearchClicked(object sender, EventArgs e) { - if(!m_searchDialog.Visible) + if (!m_searchDialog.Visible) { m_searchDialog.Show(this); if (m_searchDialog.StartPosition == FormStartPosition.CenterParent) @@ -788,7 +809,7 @@ private object MakeObjectFromSearchString(IDENTIFIER type, string search) default: return null; } } - catch(Exception) + catch (Exception) { return null; } @@ -835,12 +856,12 @@ protected override bool ProcessDialogKey(Keys keyData) private void OnMainWindowLoad(object sender, EventArgs e) { RegistrySettings settings = new RegistrySettings(); - if(!settings.HasConfirmedWarning) + if (!settings.HasConfirmedWarning) { - if(MessageBox.Show("Modifying themes can break the operating system!\r\n\r\n" + + if (MessageBox.Show("Modifying themes can break the operating system!\r\n\r\n" + "Make sure you have a recent system restore point. Only proceed if you understand " + "the risk and can deal with technical problems." - + , "msstyleEditor - Risk Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) { settings.HasConfirmedWarning = true; @@ -854,14 +875,14 @@ private void OnMainWindowLoad(object sender, EventArgs e) private void OnImageSelectIndex(object sender, EventArgs e) { - if(m_selection.Part == null) + if (m_selection.Part == null) { return; } var it = m_selection.Part.GetImageProperties(); var imgProp = it.ElementAtOrDefault(m_imageView.SelectedIndex); - if(imgProp != null) + if (imgProp != null) { m_selectedImage = UpdateImageView(imgProp); } diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index dc7dee7..1a5d403 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -14,6 +14,8 @@ public partial class PropertyViewWindow : ToolWindow private StyleState m_state; private StyleProperty m_prop; + private PropertyViewMode m_viewMode; + public delegate void PropertyChangedHandler(StyleProperty prop); public event PropertyChangedHandler OnPropertyAdded; public event PropertyChangedHandler OnPropertyRemoved; @@ -23,8 +25,30 @@ public PropertyViewWindow() InitializeComponent(); } + public void SetAnimation(Animation anim) + { + m_viewMode = PropertyViewMode.AnimationMode; + newPropertyToolStripMenuItem.Enabled = false; + deleteToolStripMenuItem.Enabled = false; + + propertyView.SelectedObject = new AnimationWrapper(anim); + } + + public void SetTimingFunction(TimingFunction timing) + { + m_viewMode = PropertyViewMode.TimingFunction; + newPropertyToolStripMenuItem.Enabled = false; + deleteToolStripMenuItem.Enabled = false; + + propertyView.SelectedObject = timing; + } + public void SetStylePart(VisualStyle style, StyleClass cls, StylePart part) { + m_viewMode = PropertyViewMode.ClassMode; + newPropertyToolStripMenuItem.Enabled = true; + deleteToolStripMenuItem.Enabled = true; + m_style = style; m_class = cls; m_part = part; @@ -78,6 +102,8 @@ private void OnPropertyAdd(object sender, EventArgs e) private void OnPropertyRemove(object sender, EventArgs e) { + if (m_viewMode != PropertyViewMode.ClassMode) + return; if (m_state == null || m_prop == null) { @@ -94,6 +120,8 @@ private void OnPropertyRemove(object sender, EventArgs e) private void OnPropertySelected(object sender, SelectedGridItemChangedEventArgs e) { + if (m_viewMode != PropertyViewMode.ClassMode) + return; const int CTX_ADD = 0; const int CTX_REM = 1; @@ -138,4 +166,11 @@ private void OnPropertySelected(object sender, SelectedGridItemChangedEventArgs } } } + + public enum PropertyViewMode + { + ClassMode, + TimingFunction, + AnimationMode, + } } diff --git a/msstyleEditorSharp/PropView/AnimationWrapper.cs b/msstyleEditorSharp/PropView/AnimationWrapper.cs new file mode 100644 index 0000000..7175713 --- /dev/null +++ b/msstyleEditorSharp/PropView/AnimationWrapper.cs @@ -0,0 +1,123 @@ +using libmsstyle; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace msstyleEditor.PropView +{ /// + /// This class is needed to avoid the depencency of System.Windows.Forms in libmsstyle at the animation flags enum + /// + public class AnimationWrapper + { + private Animation m_animation; + [Editor(typeof(EnumFlagUIEditor), typeof(System.Drawing.Design.UITypeEditor))] + [Description("The animation flags to use")] + public AnimationFlags AnimationFlags + { + get + { + return m_animation.AnimationFlags; + } + set + { + m_animation.AnimationFlags = value; + } + } + + public int StaggerDelay + { + get + { + return m_animation.StaggerDelay; + } + set + { + m_animation.StaggerDelay = value; + } + } + + public int StaggerDelayCap + { + get + { + return m_animation.StaggerDelayCap; + } + set + { + m_animation.StaggerDelayCap = value; + } + } + + public float StaggerDelayFactor + { + get + { + return m_animation.StaggerDelayFactor; + } + set + { + m_animation.StaggerDelayFactor = value; + } + } + + public int ZOrder + { + get + { + return m_animation.ZOrder; + } + set + { + m_animation.ZOrder = value; + } + } + [Description("The background part ID. Used if AnimationFlags.HasBackground is set")] + public int BackgroundPartID + { + get + { + return m_animation.BackgroundPartID; + } + set + { + m_animation.BackgroundPartID = value; + } + } + + public int TuningLevel + { + get + { + return m_animation.TuningLevel; + } + set + { + m_animation.TuningLevel = value; + } + } + + public float Perspective + { + get + { + return m_animation.Perspective; + } + set + { + m_animation.Perspective = value; + } + } + + [Description("The list of transforms. Can be zero.")] + public List Transforms { get { return m_animation.Transforms; } } + + public AnimationWrapper(Animation wrapper) + { + this.m_animation = wrapper; + } + } +} diff --git a/msstyleEditorSharp/PropView/EnumFlagCheckedListBox.cs b/msstyleEditorSharp/PropView/EnumFlagCheckedListBox.cs new file mode 100644 index 0000000..f064d29 --- /dev/null +++ b/msstyleEditorSharp/PropView/EnumFlagCheckedListBox.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace msstyleEditor.PropView +{ + public class EnumFlagCheckedListBox : CheckedListBox + { + private System.ComponentModel.Container components = null; + + public EnumFlagCheckedListBox() + { + // This call is required by the Windows.Forms Form Designer. + InitializeComponent(); + + // TODO: Add any initialization after the InitForm call + + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (components != null) + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + private void InitializeComponent() + { + // + // FlaggedCheckedListBox + // + this.CheckOnClick = true; + + } + #endregion + + // Adds an integer value and its associated description + public EnumFlagCheckedListBoxItem Add(int v, string c) + { + EnumFlagCheckedListBoxItem item = new EnumFlagCheckedListBoxItem(v, c); + Items.Add(item); + return item; + } + + public EnumFlagCheckedListBoxItem Add(EnumFlagCheckedListBoxItem item) + { + Items.Add(item); + return item; + } + + protected override void OnItemCheck(ItemCheckEventArgs e) + { + base.OnItemCheck(e); + + if (isUpdatingCheckStates) + return; + + // Get the checked/unchecked item + EnumFlagCheckedListBoxItem item = Items[e.Index] as EnumFlagCheckedListBoxItem; + // Update other items + UpdateCheckedItems(item, e.NewValue); + } + + // Checks/Unchecks items depending on the give bitvalue + protected void UpdateCheckedItems(int value) + { + + isUpdatingCheckStates = true; + + // Iterate over all items + for (int i = 0; i < Items.Count; i++) + { + EnumFlagCheckedListBoxItem item = Items[i] as EnumFlagCheckedListBoxItem; + + if (item.value == 0) + { + SetItemChecked(i, value == 0); + } + else + { + + // If the bit for the current item is on in the bitvalue, check it + if ((item.value & value) == item.value && item.value != 0) + SetItemChecked(i, true); + // Otherwise uncheck it + else + SetItemChecked(i, false); + } + } + + isUpdatingCheckStates = false; + + } + + // Updates items in the checklistbox + // composite = The item that was checked/unchecked + // cs = The check state of that item + protected void UpdateCheckedItems(EnumFlagCheckedListBoxItem composite, CheckState cs) + { + + // If the value of the item is 0, call directly. + if (composite.value == 0) + UpdateCheckedItems(0); + + + // Get the total value of all checked items + int sum = 0; + for (int i = 0; i < Items.Count; i++) + { + EnumFlagCheckedListBoxItem item = Items[i] as EnumFlagCheckedListBoxItem; + + // If item is checked, add its value to the sum. + if (GetItemChecked(i)) + sum |= item.value; + } + + // If the item has been unchecked, remove its bits from the sum + if (cs == CheckState.Unchecked) + sum = sum & (~composite.value); + // If the item has been checked, combine its bits with the sum + else + sum |= composite.value; + + // Update all items in the checklistbox based on the final bit value + UpdateCheckedItems(sum); + + } + + private bool isUpdatingCheckStates = false; + + // Gets the current bit value corresponding to all checked items + public int GetCurrentValue() + { + int sum = 0; + + for (int i = 0; i < Items.Count; i++) + { + EnumFlagCheckedListBoxItem item = Items[i] as EnumFlagCheckedListBoxItem; + + if (GetItemChecked(i)) + sum |= item.value; + } + + return sum; + } + + Type enumType; + Enum enumValue; + + // Adds items to the checklistbox based on the members of the enum + private void FillEnumMembers() + { + foreach (string name in Enum.GetNames(enumType)) + { + object val = Enum.Parse(enumType, name); + int intVal = (int)Convert.ChangeType(val, typeof(int)); + + Add(intVal, name); + } + } + + // Checks/unchecks items based on the current value of the enum variable + private void ApplyEnumValue() + { + int intVal = (int)Convert.ChangeType(enumValue, typeof(int)); + UpdateCheckedItems(intVal); + + } + + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public Enum EnumValue + { + get + { + object e = Enum.ToObject(enumType, GetCurrentValue()); + return (Enum)e; + } + set + { + + Items.Clear(); + enumValue = value; // Store the current enum value + enumType = value.GetType(); // Store enum type + FillEnumMembers(); // Add items for enum members + ApplyEnumValue(); // Check/uncheck items depending on enum value + + } + } + } + + // Represents an item in the checklistbox + public class EnumFlagCheckedListBoxItem + { + public EnumFlagCheckedListBoxItem(int v, string c) + { + value = v; + caption = c; + } + + public override string ToString() + { + return caption; + } + + // Returns true if the value corresponds to a single bit being set + public bool IsFlag + { + get + { + return ((value & (value - 1)) == 0); + } + } + + // Returns true if this value is a member of the composite bit value + public bool IsMemberFlag(EnumFlagCheckedListBoxItem composite) + { + return (IsFlag && ((value & composite.value) == value)); + } + + public int value; + public string caption; + } +} diff --git a/msstyleEditorSharp/PropView/EnumFlagUIEditor.cs b/msstyleEditorSharp/PropView/EnumFlagUIEditor.cs new file mode 100644 index 0000000..a0b851d --- /dev/null +++ b/msstyleEditorSharp/PropView/EnumFlagUIEditor.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing.Design; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace msstyleEditor.PropView +{ + public class EnumFlagUIEditor : UITypeEditor + { + private EnumFlagCheckedListBox flagEnumCB; + + public EnumFlagUIEditor() + { + flagEnumCB = new EnumFlagCheckedListBox(); + flagEnumCB.BorderStyle = BorderStyle.None; + } + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + if (context != null + && context.Instance != null + && provider != null) + { + + IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); + + if (edSvc != null) + { + + Enum e = (Enum)Convert.ChangeType(value, context.PropertyDescriptor.PropertyType); + flagEnumCB.EnumValue = e; + edSvc.DropDownControl(flagEnumCB); + return flagEnumCB.EnumValue; + + } + } + return null; + } + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.DropDown; + } + } +} diff --git a/msstyleEditorSharp/msstyleEditorSharp.csproj b/msstyleEditorSharp/msstyleEditorSharp.csproj index c0c20b7..652540c 100644 --- a/msstyleEditorSharp/msstyleEditorSharp.csproj +++ b/msstyleEditorSharp/msstyleEditorSharp.csproj @@ -9,7 +9,7 @@ WinExe msstyleEditor msstyleEditor - v4.5 + v4.6 512 true @@ -29,6 +29,7 @@ 1.0.0.%2a false true + AnyCPU @@ -166,6 +167,11 @@ Resources.resx + + Component + + + diff --git a/msstyleEditorSharp/packages.config b/msstyleEditorSharp/packages.config index 7370310..68e231d 100644 --- a/msstyleEditorSharp/packages.config +++ b/msstyleEditorSharp/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file From 9eb75f4a18359e9d835217e65f5f1e2764db1f30 Mon Sep 17 00:00:00 2001 From: Misha Date: Sat, 9 Sep 2023 08:05:11 -0400 Subject: [PATCH 2/6] Begin adding support for adding new states --- libmsstyle/Animation.cs | 26 ++- libmsstyle/CubicBezierTimingFunction.cs | 5 + libmsstyle/TimingFunction.cs | 20 ++- msstyleEditorSharp/Dialogs/ClassView.cs | 19 +- msstyleEditorSharp/Dialogs/MainWindow.cs | 4 +- msstyleEditorSharp/Dialogs/PropertyView.cs | 12 +- .../PropView/TypeDescriptors.cs | 164 +++++++++++++++++- msstyleEditorSharp/msstyleEditorSharp.csproj | 5 + 8 files changed, 239 insertions(+), 16 deletions(-) diff --git a/libmsstyle/Animation.cs b/libmsstyle/Animation.cs index 7c50b58..049ac5d 100644 --- a/libmsstyle/Animation.cs +++ b/libmsstyle/Animation.cs @@ -476,6 +476,16 @@ public class Animation { 3, "UnknownState(3)" }, { 4, "UnknownState(4)" } }) + }, + { 94, new AnimationStates("WindowMinimizeWin11", new Dictionary + { + { 1, "Target" }, + }) + }, + { 95, new AnimationStates("WindowRestoreWin11", new Dictionary + { + { 1, "Target" }, + }) } }; public Animation(byte[] data, ref int start, PropertyHeader header) @@ -505,8 +515,20 @@ public Animation(byte[] data, ref int start, PropertyHeader header) Transforms.Add(t); start += GetPaddingForSize(t.StructureSize); } - - + } + /// + /// Create a new animation + /// + /// Header of the animations class + /// Animation part + /// Animation state + public Animation(PropertyHeader animationsHeader, int part, int state) + { + PropertiesIndex = 16; + TransformsIndex = 56; + Header = new PropertyHeader(20000, animationsHeader.typeID); + Header.stateID = state; + Header.partID = part; } int GetPaddingForSize(int size) diff --git a/libmsstyle/CubicBezierTimingFunction.cs b/libmsstyle/CubicBezierTimingFunction.cs index 6612c24..99bc900 100644 --- a/libmsstyle/CubicBezierTimingFunction.cs +++ b/libmsstyle/CubicBezierTimingFunction.cs @@ -23,6 +23,11 @@ public CubicBezierTimingFunction(byte[] data, int start) RY1 = BitConverter.ToSingle(data, start + 12); } + public CubicBezierTimingFunction() + { + + } + internal void Write(BinaryWriter w) { w.Write(RX0); diff --git a/libmsstyle/TimingFunction.cs b/libmsstyle/TimingFunction.cs index 42d060c..becee3e 100644 --- a/libmsstyle/TimingFunction.cs +++ b/libmsstyle/TimingFunction.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.IO; using System.Linq; +using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading.Tasks; @@ -39,6 +40,18 @@ public class TimingFunction {64 , "AppLaunchRotateBounceDelayed"}, {65 , "DesktopWithPop"}, }; + /// + /// Create a new timing function + /// + /// Header of the timingfunctions class + /// the part ID of the timing function + public TimingFunction(PropertyHeader timingFunctionHeader, int partId) + { + this.Header = new PropertyHeader(20100, timingFunctionHeader.typeID); + Header.classID = 333; //id of TimingFunction class + Header.partID = partId; + CubicBezier = new CubicBezierTimingFunction(); + } public TimingFunction(byte[] data, int start, PropertyHeader header) { this.Header = header; @@ -56,13 +69,18 @@ public TimingFunction(byte[] data, int start, PropertyHeader header) } public void Write(BinaryWriter bw) { + if (Type == TimingFunctionType.Undefined) + Header.sizeInBytes = 4; + else if (Type == TimingFunctionType.CubicBezier) + Header.sizeInBytes = 4 + 16; + bw.Write(Header.Serialize()); WriteData(bw); } public void WriteData(BinaryWriter w) { w.Write((int)Type); - if(Type == TimingFunctionType.CubicBezier) + if (Type == TimingFunctionType.CubicBezier) { CubicBezier.Write(w); } diff --git a/msstyleEditorSharp/Dialogs/ClassView.cs b/msstyleEditorSharp/Dialogs/ClassView.cs index 844867f..9e7769d 100644 --- a/msstyleEditorSharp/Dialogs/ClassView.cs +++ b/msstyleEditorSharp/Dialogs/ClassView.cs @@ -1,4 +1,5 @@ using libmsstyle; +using msstyleEditor.PropView; using System; using System.Collections.Generic; using System.ComponentModel; @@ -65,6 +66,7 @@ public void SetVisualStyle(VisualStyle style) TreeNode partNode; bool exists = false; + if (nodes.ContainsKey(animation.Header.partID)) { exists = true; @@ -72,7 +74,7 @@ public void SetVisualStyle(VisualStyle style) } else { - //check if the name is known + //Create a new state node if (Animation.AnimationNameMap.ContainsKey(animation.Header.partID)) { partNode = new TreeNode(Animation.AnimationNameMap[animation.Header.partID].AnimationName); @@ -81,6 +83,7 @@ public void SetVisualStyle(VisualStyle style) { partNode = new TreeNode("Unknown part " + animation.Header.partID); } + partNode.Tag = new AnimationTypeDescriptor(animation); } //Add the state @@ -91,7 +94,7 @@ public void SetVisualStyle(VisualStyle style) if (Animation.AnimationNameMap.ContainsKey(animation.Header.partID)) { - if(Animation.AnimationNameMap[animation.Header.partID].AnimationStateDict.ContainsKey(animation.Header.stateID)) + if (Animation.AnimationNameMap[animation.Header.partID].AnimationStateDict.ContainsKey(animation.Header.stateID)) { stateName = Animation.AnimationNameMap[animation.Header.partID].AnimationStateDict[animation.Header.stateID]; } @@ -102,12 +105,14 @@ public void SetVisualStyle(VisualStyle style) } else { - stateName = "Unknown state: "+ animation.Header.stateID; + stateName = "Unknown state: " + animation.Header.stateID; + } + + //add the new state if there is another state + if (exists) + { + ((AnimationTypeDescriptor)partNode.Tag).AddState(animation); } - //add the state - var stateNode = new TreeNode(stateName); - stateNode.Tag = animation; - partNode.Nodes.Add(stateNode); //add the part node if it wasnt added if (!exists) diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index 28cc2ee..6e5501a 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -28,7 +28,7 @@ public partial class MainWindow : Form private RenderView m_renderView; private TimingFunction m_selectedTimingFunction; - private Animation m_selectedAnimation; + private AnimationTypeDescriptor m_selectedAnimation; public MainWindow() { InitializeComponent(); @@ -464,7 +464,7 @@ private void OnTreeItemSelected(object sender, TreeViewEventArgs e) return; } - Animation animation = e.Node.Tag as Animation; + AnimationTypeDescriptor animation = e.Node.Tag as AnimationTypeDescriptor; if (animation != null) { m_selectedAnimation = animation; diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index 1a5d403..dc4657f 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -1,6 +1,7 @@ using libmsstyle; using msstyleEditor.PropView; using System; +using System.Collections.Generic; using System.Windows.Forms; namespace msstyleEditor.Dialogs @@ -25,13 +26,13 @@ public PropertyViewWindow() InitializeComponent(); } - public void SetAnimation(Animation anim) + public void SetAnimation(AnimationTypeDescriptor anim) { m_viewMode = PropertyViewMode.AnimationMode; newPropertyToolStripMenuItem.Enabled = false; deleteToolStripMenuItem.Enabled = false; - propertyView.SelectedObject = new AnimationWrapper(anim); + propertyView.SelectedObject = anim; } public void SetTimingFunction(TimingFunction timing) @@ -71,6 +72,13 @@ public void RemoveSelectedProperty() private void OnPropertyAdd(object sender, EventArgs e) { + if (m_style != null && m_class != null) + { + if (m_class.ClassName == "animations") + { + + } + } if(m_style == null || m_class == null || m_part == null diff --git a/msstyleEditorSharp/PropView/TypeDescriptors.cs b/msstyleEditorSharp/PropView/TypeDescriptors.cs index a0f65b7..f8e30aa 100644 --- a/msstyleEditorSharp/PropView/TypeDescriptors.cs +++ b/msstyleEditorSharp/PropView/TypeDescriptors.cs @@ -2,9 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Text; -using System.Threading.Tasks; namespace msstyleEditor.PropView { @@ -135,7 +133,106 @@ public object GetPropertyOwner(PropertyDescriptor pd) } #endregion } + public class AnimationTypeDescriptor :ICustomTypeDescriptor + { + public List Animations = new List(); + public AnimationTypeDescriptor(Animation animation) + { + Animations.Add(animation); + } + + public void AddState(Animation animation) + { + Animations.Add(animation); + } + public String GetClassName() + { + return System.ComponentModel.TypeDescriptor.GetClassName(this, true); + } + + public AttributeCollection GetAttributes() + { + return System.ComponentModel.TypeDescriptor.GetAttributes(this, true); + } + + public String GetComponentName() + { + return System.ComponentModel.TypeDescriptor.GetComponentName(this, true); + } + + public TypeConverter GetConverter() + { + return System.ComponentModel.TypeDescriptor.GetConverter(this, true); + } + + public EventDescriptor GetDefaultEvent() + { + return System.ComponentModel.TypeDescriptor.GetDefaultEvent(this, true); + } + + public PropertyDescriptor GetDefaultProperty() + { + return System.ComponentModel.TypeDescriptor.GetDefaultProperty(this, true); + } + + /// + /// GetEditor + /// + /// editorBaseType + /// object + public object GetEditor(Type editorBaseType) + { + return System.ComponentModel.TypeDescriptor.GetEditor(this, editorBaseType, true); + } + + public EventDescriptorCollection GetEvents(Attribute[] attributes) + { + return System.ComponentModel.TypeDescriptor.GetEvents(this, attributes, true); + } + public EventDescriptorCollection GetEvents() + { + return System.ComponentModel.TypeDescriptor.GetEvents(this, true); + } + + internal static string MakeCategoryNameWithSortingHack(StyleState state) + { + // We append a lot of \t for the category that shall be shown on top. + // Subsequent categories have each one \t less then the one above. + int numNonPrintable = 30 - state.StateId; // 30 ought to be enough + StringBuilder sb = new StringBuilder(30); + for (int i = 0; i < numNonPrintable; ++i) + { + sb.Append('\t'); + } + sb.AppendFormat("{0} - {1}", state.StateId, state.StateName); + return sb.ToString(); + } + + public PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { + List propDesc = new List(); + foreach (var state in Animations) + { + foreach(var item in state.GetType().GetProperties()) + { + propDesc.Add(new AnimationPropertyDescriptior(item, state, attributes)); + } + } + + return new PropertyDescriptorCollection(propDesc.ToArray()); + } + + public PropertyDescriptorCollection GetProperties() + { + return System.ComponentModel.TypeDescriptor.GetProperties(this, true); + } + + public object GetPropertyOwner(PropertyDescriptor pd) + { + return this; + } + } public class StylePropertyDescriptor : PropertyDescriptor { PropertyInfo m_info; @@ -284,4 +381,67 @@ public StyleState StyleState get { return m_State; } } } + + public class AnimationPropertyDescriptior : PropertyDescriptor + { + public override Type ComponentType => null; + + public override bool IsReadOnly => !m_fi.CanWrite; + + public override Type PropertyType => m_fi.PropertyType; + private System.Reflection.PropertyInfo m_fi; + private Animation m_animation; + private string m_category; + public override string Category => m_category; + public AnimationPropertyDescriptior(System.Reflection.PropertyInfo fi, Animation animation, Attribute[] attrs) + : base(fi.Name, attrs) + { + this.m_fi = fi; + this.m_animation = animation; + + //check if the state ID is known + if(Animation.AnimationNameMap.ContainsKey(animation.Header.partID)) + { + var map = Animation.AnimationNameMap[animation.Header.partID]; + if (map.AnimationStateDict.ContainsKey(animation.Header.stateID)) + { + var state = map.AnimationStateDict[animation.Header.stateID]; + this.m_category = $"{animation.Header.stateID} - {state}"; + } + else + { + this.m_category = "State " + animation.Header.stateID; + } + } + else + { + this.m_category = "State " + animation.Header.stateID; + } + } + + public override bool CanResetValue(object component) + { + return false; + } + + public override object GetValue(object component) + { + return m_fi.GetValue(m_animation); + } + + public override void ResetValue(object component) + { + + } + + public override void SetValue(object component, object value) + { + m_fi.SetValue(m_animation, value); + } + + public override bool ShouldSerializeValue(object component) + { + return false; + } + } } diff --git a/msstyleEditorSharp/msstyleEditorSharp.csproj b/msstyleEditorSharp/msstyleEditorSharp.csproj index 652540c..5b739db 100644 --- a/msstyleEditorSharp/msstyleEditorSharp.csproj +++ b/msstyleEditorSharp/msstyleEditorSharp.csproj @@ -112,6 +112,9 @@ Form + + Form + ClassView.cs @@ -166,12 +169,14 @@ True Resources.resx + Component + From 6f17040cdac4e0862854e3e7f268b11086ad9338 Mon Sep 17 00:00:00 2001 From: Misha Date: Fri, 6 Oct 2023 19:48:50 -0400 Subject: [PATCH 3/6] implement property adding --- libmsstyle/Animation.cs | 7 +- libmsstyle/StyleProperty.cs | 5 +- libmsstyle/Transform.cs | 3 +- msstyleEditorSharp/Dialogs/MainWindow.cs | 28 ++-- .../Dialogs/NewAnimationDialog.Designer.cs | 112 ++++++++++++++++ .../Dialogs/NewAnimationDialog.cs | 56 ++++++++ .../Dialogs/NewAnimationDialog.resx | 120 +++++++++++++++++ msstyleEditorSharp/Dialogs/PropertyView.cs | 16 ++- .../PropView/AnimationWrapper.cs | 123 ------------------ .../PropView/TypeDescriptors.cs | 18 +++ msstyleEditorSharp/msstyleEditorSharp.csproj | 13 +- 11 files changed, 359 insertions(+), 142 deletions(-) create mode 100644 msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs create mode 100644 msstyleEditorSharp/Dialogs/NewAnimationDialog.cs create mode 100644 msstyleEditorSharp/Dialogs/NewAnimationDialog.resx delete mode 100644 msstyleEditorSharp/PropView/AnimationWrapper.cs diff --git a/libmsstyle/Animation.cs b/libmsstyle/Animation.cs index ed9330f..4fba0a7 100644 --- a/libmsstyle/Animation.cs +++ b/libmsstyle/Animation.cs @@ -14,7 +14,7 @@ public class Animation public int PropertiesIndex; public int TransformsIndex; public AnimationFlags AnimationFlags { get; set; } - public int TransformCount { get; set; } + private int TransformCount; public int StaggerDelay { get; set; } public int StaggerDelayCap { get; set; } public float StaggerDelayFactor { get; set; } @@ -23,6 +23,7 @@ public class Animation public int TuningLevel { get; set; } public float Perspective { get; set; } private List _transforms = new List(); + [Description("The list of animations to play at the same time.")] public List Transforms { get { return _transforms; } } public PropertyHeader Header; public Animation(byte[] data, ref int start, PropertyHeader header) @@ -59,11 +60,11 @@ public Animation(byte[] data, ref int start, PropertyHeader header) /// Header of the animations class /// Animation part /// Animation state - public Animation(PropertyHeader animationsHeader, int part, int state) + public Animation(PropertyHeader header, int part, int state) { PropertiesIndex = 16; TransformsIndex = 56; - Header = new PropertyHeader(20000, animationsHeader.typeID); + Header = header; Header.stateID = state; Header.partID = part; } diff --git a/libmsstyle/StyleProperty.cs b/libmsstyle/StyleProperty.cs index 64196b9..6316e02 100644 --- a/libmsstyle/StyleProperty.cs +++ b/libmsstyle/StyleProperty.cs @@ -129,8 +129,11 @@ public bool IsValid() classID > 500) // guessing here to be stateless return false; + if (nameID == 20000) //Animation + return true; + // Basic range check - if (typeID < (int)IDENTIFIER.ENUM || typeID >= (int)IDENTIFIER.COLORSCHEMES) + if (typeID < (int)IDENTIFIER.ENUM || typeID >= (int)IDENTIFIER.COLORSCHEMES) return false; // Some color and font props use an type id as name id. diff --git a/libmsstyle/Transform.cs b/libmsstyle/Transform.cs index c19a5a7..02fcc16 100644 --- a/libmsstyle/Transform.cs +++ b/libmsstyle/Transform.cs @@ -17,7 +17,7 @@ public class Transform public int DurationTime { get; set; } public TransformFlag Flags { get; set; } [TypeConverter(typeof(ExpandableObjectConverter))] - + [Description("3D animation. No longer working in Windows 10+")] public Transform3D Transform3DStructure { get; set; } [TypeConverter(typeof(ExpandableObjectConverter))] @@ -129,6 +129,7 @@ public enum TransformType Scale3D = 259, Roatate3D = 260, } + [Flags] public enum TransformFlag { diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index 478a94e..da89bea 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -696,12 +696,21 @@ private void OnPropertyAdd(object sender, EventArgs e) m_propertyView.ShowPropertyAddDialog(); } - private void OnPropertyAdded(StyleProperty prop) + private void OnPropertyAdded(object prop) { - // refresh gui to account for new image property - if (prop.IsImageProperty()) + if (prop is StyleProperty styleProp) { - DisplayPart(m_selection.Class, m_selection.Part); + // refresh gui to account for new image property + if (styleProp.IsImageProperty()) + { + DisplayPart(m_selection.Class, m_selection.Part); + } + } + + if (prop is Animation animation) + { + m_selectedAnimation = new AnimationTypeDescriptor(animation); + m_propertyView.SetAnimation(m_selectedAnimation); } } @@ -710,12 +719,15 @@ private void OnPropertyRemove(object sender, EventArgs e) m_propertyView.RemoveSelectedProperty(); } - private void OnPropertyRemoved(StyleProperty prop) + private void OnPropertyRemoved(object prop) { - // refresh gui to account for removed image property - if (prop.IsImageProperty()) + if(prop is StyleProperty styleProp) { - DisplayPart(m_selection.Class, m_selection.Part); + // refresh gui to account for removed image property + if (styleProp.IsImageProperty()) + { + DisplayPart(m_selection.Class, m_selection.Part); + } } } diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs b/msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs new file mode 100644 index 0000000..46454cc --- /dev/null +++ b/msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs @@ -0,0 +1,112 @@ +namespace msstyleEditor.Dialogs +{ + partial class NewAnimationDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.txtPartId = new System.Windows.Forms.TextBox(); + this.txtStateId = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.btnCreate = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // txtPartId + // + this.txtPartId.Location = new System.Drawing.Point(107, 13); + this.txtPartId.Name = "txtPartId"; + this.txtPartId.Size = new System.Drawing.Size(191, 33); + this.txtPartId.TabIndex = 0; + // + // txtStateId + // + this.txtStateId.Location = new System.Drawing.Point(107, 58); + this.txtStateId.Name = "txtStateId"; + this.txtStateId.Size = new System.Drawing.Size(188, 33); + this.txtStateId.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(74, 28); + this.label1.TabIndex = 2; + this.label1.Text = "Part ID:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 58); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(84, 28); + this.label2.TabIndex = 3; + this.label2.Text = "State ID:"; + // + // btnCreate + // + this.btnCreate.Font = new System.Drawing.Font("Segoe UI", 8.142858F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnCreate.Location = new System.Drawing.Point(189, 106); + this.btnCreate.Name = "btnCreate"; + this.btnCreate.Size = new System.Drawing.Size(109, 45); + this.btnCreate.TabIndex = 4; + this.btnCreate.Text = "Create"; + this.btnCreate.UseVisualStyleBackColor = true; + this.btnCreate.Click += new System.EventHandler(this.btnCreate_Click); + // + // NewAnimationDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(168F, 168F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(316, 163); + this.Controls.Add(this.btnCreate); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtStateId); + this.Controls.Add(this.txtPartId); + this.Font = new System.Drawing.Font("Segoe UI", 8.142858F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "NewAnimationDialog"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Add new animation"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtPartId; + private System.Windows.Forms.TextBox txtStateId; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button btnCreate; + } +} \ No newline at end of file diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs b/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs new file mode 100644 index 0000000..584a8e8 --- /dev/null +++ b/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs @@ -0,0 +1,56 @@ +using libmsstyle; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace msstyleEditor.Dialogs +{ + public partial class NewAnimationDialog : Form + { + public int PartID { get; private set; } + public int StateID { get; private set; } + public NewAnimationDialog() + { + InitializeComponent(); + } + + private void btnCreate_Click(object sender, EventArgs e) + { + if(!int.TryParse(txtPartId.Text, out int PartID)) + { + MessageBox.Show("Part ID must be a number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.PartID = PartID; + + if (!int.TryParse(txtPartId.Text, out int StateID)) + { + MessageBox.Show("State ID must be a number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.StateID = StateID; + + DialogResult = DialogResult.OK; + } + + public new Animation ShowDialog(PropertyHeader header) + { + if(base.ShowDialog() == DialogResult.OK) + { + return new Animation(header, PartID, StateID); + } + else + { + return null; + } + } + } +} diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.resx b/msstyleEditorSharp/Dialogs/NewAnimationDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/msstyleEditorSharp/Dialogs/NewAnimationDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index dc4657f..4c0f952 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -17,7 +17,7 @@ public partial class PropertyViewWindow : ToolWindow private PropertyViewMode m_viewMode; - public delegate void PropertyChangedHandler(StyleProperty prop); + public delegate void PropertyChangedHandler(object prop); public event PropertyChangedHandler OnPropertyAdded; public event PropertyChangedHandler OnPropertyRemoved; @@ -76,7 +76,19 @@ private void OnPropertyAdd(object sender, EventArgs e) { if (m_class.ClassName == "animations") { - + var dlg2 = new NewAnimationDialog(); + //typeid is the same for all animations + var anim = dlg2.ShowDialog(new PropertyHeader(20000, m_style.Animations[0].Header.typeID) { classID = m_class.ClassId}); + if (anim != null) + { + m_style.Animations.Add(anim); + if (OnPropertyAdded != null) + { + OnPropertyAdded(anim); + } + propertyView.Refresh(); + } + return; } } if(m_style == null diff --git a/msstyleEditorSharp/PropView/AnimationWrapper.cs b/msstyleEditorSharp/PropView/AnimationWrapper.cs deleted file mode 100644 index 7175713..0000000 --- a/msstyleEditorSharp/PropView/AnimationWrapper.cs +++ /dev/null @@ -1,123 +0,0 @@ -using libmsstyle; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace msstyleEditor.PropView -{ /// - /// This class is needed to avoid the depencency of System.Windows.Forms in libmsstyle at the animation flags enum - /// - public class AnimationWrapper - { - private Animation m_animation; - [Editor(typeof(EnumFlagUIEditor), typeof(System.Drawing.Design.UITypeEditor))] - [Description("The animation flags to use")] - public AnimationFlags AnimationFlags - { - get - { - return m_animation.AnimationFlags; - } - set - { - m_animation.AnimationFlags = value; - } - } - - public int StaggerDelay - { - get - { - return m_animation.StaggerDelay; - } - set - { - m_animation.StaggerDelay = value; - } - } - - public int StaggerDelayCap - { - get - { - return m_animation.StaggerDelayCap; - } - set - { - m_animation.StaggerDelayCap = value; - } - } - - public float StaggerDelayFactor - { - get - { - return m_animation.StaggerDelayFactor; - } - set - { - m_animation.StaggerDelayFactor = value; - } - } - - public int ZOrder - { - get - { - return m_animation.ZOrder; - } - set - { - m_animation.ZOrder = value; - } - } - [Description("The background part ID. Used if AnimationFlags.HasBackground is set")] - public int BackgroundPartID - { - get - { - return m_animation.BackgroundPartID; - } - set - { - m_animation.BackgroundPartID = value; - } - } - - public int TuningLevel - { - get - { - return m_animation.TuningLevel; - } - set - { - m_animation.TuningLevel = value; - } - } - - public float Perspective - { - get - { - return m_animation.Perspective; - } - set - { - m_animation.Perspective = value; - } - } - - [Description("The list of transforms. Can be zero.")] - public List Transforms { get { return m_animation.Transforms; } } - - public AnimationWrapper(Animation wrapper) - { - this.m_animation = wrapper; - } - } -} diff --git a/msstyleEditorSharp/PropView/TypeDescriptors.cs b/msstyleEditorSharp/PropView/TypeDescriptors.cs index b9bab46..decb69a 100644 --- a/msstyleEditorSharp/PropView/TypeDescriptors.cs +++ b/msstyleEditorSharp/PropView/TypeDescriptors.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Drawing.Design; using System.Text; namespace msstyleEditor.PropView @@ -393,6 +394,7 @@ public class AnimationPropertyDescriptior : PropertyDescriptor private Animation m_animation; private string m_category; public override string Category => m_category; + public AnimationPropertyDescriptior(System.Reflection.PropertyInfo fi, Animation animation, Attribute[] attrs) : base(fi.Name, attrs) { @@ -416,6 +418,21 @@ public AnimationPropertyDescriptior(System.Reflection.PropertyInfo fi, Animation { this.m_category = "State " + animation.Header.stateID; } + List newAtribs = new List(); + if (fi.Name == "AnimationFlags") + { + newAtribs.Add(new EditorAttribute(typeof(EnumFlagUIEditor), typeof(UITypeEditor))); + } + //add description + var desc = fi.GetCustomAttributes(false); + foreach (var item in desc) + { + if(item is DescriptionAttribute) + { + newAtribs.Add(item as DescriptionAttribute); + } + } + this.AttributeArray = newAtribs.ToArray(); } public override bool CanResetValue(object component) @@ -430,6 +447,7 @@ public override object GetValue(object component) public override void ResetValue(object component) { + } public override void SetValue(object component, object value) diff --git a/msstyleEditorSharp/msstyleEditorSharp.csproj b/msstyleEditorSharp/msstyleEditorSharp.csproj index 9a846f5..11d303a 100644 --- a/msstyleEditorSharp/msstyleEditorSharp.csproj +++ b/msstyleEditorSharp/msstyleEditorSharp.csproj @@ -112,9 +112,6 @@ Form - - Form - ClassView.cs @@ -136,6 +133,12 @@ LicenseDialog.cs + + Form + + + NewAnimationDialog.cs + Form @@ -169,7 +172,6 @@ True Resources.resx - Component @@ -220,6 +222,9 @@ MainWindow.cs Designer + + NewAnimationDialog.cs + PropertyView.cs From e8f3741901013d1be891d0692193a3ade7c2407d Mon Sep 17 00:00:00 2001 From: Misha Date: Fri, 6 Oct 2023 18:59:54 -0400 Subject: [PATCH 4/6] Implement animation adding/removing --- libmsstyle/StyleProperty.cs | 4 +- msstyleEditorSharp/Dialogs/ClassView.cs | 7 + msstyleEditorSharp/Dialogs/MainWindow.cs | 11 +- .../Dialogs/NewAnimationDialog.cs | 2 +- msstyleEditorSharp/Dialogs/PropertyView.cs | 163 ++++++++++++------ .../PropView/TypeDescriptors.cs | 2 +- 6 files changed, 134 insertions(+), 55 deletions(-) diff --git a/libmsstyle/StyleProperty.cs b/libmsstyle/StyleProperty.cs index 6316e02..207e5f4 100644 --- a/libmsstyle/StyleProperty.cs +++ b/libmsstyle/StyleProperty.cs @@ -131,8 +131,8 @@ public bool IsValid() if (nameID == 20000) //Animation return true; - - // Basic range check + + // Basic range check if (typeID < (int)IDENTIFIER.ENUM || typeID >= (int)IDENTIFIER.COLORSCHEMES) return false; diff --git a/msstyleEditorSharp/Dialogs/ClassView.cs b/msstyleEditorSharp/Dialogs/ClassView.cs index 1507ef2..f61ab38 100644 --- a/msstyleEditorSharp/Dialogs/ClassView.cs +++ b/msstyleEditorSharp/Dialogs/ClassView.cs @@ -124,7 +124,14 @@ public void SetVisualStyle(VisualStyle style) } classView.EndUpdate(); } + public void Refresh() + { + classView.BeginUpdate(); + classView.Nodes.Clear(); + classView.EndUpdate(); + SetVisualStyle(m_style); + } bool m_endReached = false; public void FindNextNode(SearchDialog.SearchMode mode, IDENTIFIER type, string searchString, object searchObject) { diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index da89bea..47316f3 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -459,7 +459,7 @@ private void OnTreeItemSelected(object sender, TreeViewEventArgs e) if (func != null) { m_selectedTimingFunction = func; - m_propertyView.SetTimingFunction(func); + m_propertyView.SetTimingFunction(m_style, func); return; } @@ -467,7 +467,7 @@ private void OnTreeItemSelected(object sender, TreeViewEventArgs e) if (animation != null) { m_selectedAnimation = animation; - m_propertyView.SetAnimation(animation); + m_propertyView.SetAnimation(m_style, animation); return; } @@ -710,7 +710,7 @@ private void OnPropertyAdded(object prop) if (prop is Animation animation) { m_selectedAnimation = new AnimationTypeDescriptor(animation); - m_propertyView.SetAnimation(m_selectedAnimation); + m_propertyView.SetAnimation(m_style, m_selectedAnimation); } } @@ -729,6 +729,11 @@ private void OnPropertyRemoved(object prop) DisplayPart(m_selection.Class, m_selection.Part); } } + else if (prop is Animation || prop is TimingFunction) + { + m_classView.Refresh(); + m_propertyView.SetStylePart(null, null, null); + } } private void OnSearchClicked(object sender, EventArgs e) diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs b/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs index 584a8e8..8055f4e 100644 --- a/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs +++ b/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs @@ -30,7 +30,7 @@ private void btnCreate_Click(object sender, EventArgs e) this.PartID = PartID; - if (!int.TryParse(txtPartId.Text, out int StateID)) + if (!int.TryParse(txtStateId.Text, out int StateID)) { MessageBox.Show("State ID must be a number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index 4c0f952..269b482 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -2,6 +2,7 @@ using msstyleEditor.PropView; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Windows.Forms; namespace msstyleEditor.Dialogs @@ -15,19 +16,24 @@ public partial class PropertyViewWindow : ToolWindow private StyleState m_state; private StyleProperty m_prop; + private AnimationTypeDescriptor m_SelectedAnimation; + private Animation m_SelectedAnimationPart; + private PropertyViewMode m_viewMode; public delegate void PropertyChangedHandler(object prop); public event PropertyChangedHandler OnPropertyAdded; public event PropertyChangedHandler OnPropertyRemoved; + public PropertyViewWindow() { InitializeComponent(); } - public void SetAnimation(AnimationTypeDescriptor anim) + public void SetAnimation(VisualStyle style, AnimationTypeDescriptor anim) { + m_style = style; m_viewMode = PropertyViewMode.AnimationMode; newPropertyToolStripMenuItem.Enabled = false; deleteToolStripMenuItem.Enabled = false; @@ -35,8 +41,9 @@ public void SetAnimation(AnimationTypeDescriptor anim) propertyView.SelectedObject = anim; } - public void SetTimingFunction(TimingFunction timing) + public void SetTimingFunction(VisualStyle style, TimingFunction timing) { + m_style = style; m_viewMode = PropertyViewMode.TimingFunction; newPropertyToolStripMenuItem.Enabled = false; deleteToolStripMenuItem.Enabled = false; @@ -122,67 +129,127 @@ private void OnPropertyAdd(object sender, EventArgs e) private void OnPropertyRemove(object sender, EventArgs e) { - if (m_viewMode != PropertyViewMode.ClassMode) - return; - if (m_state == null || - m_prop == null) + if (m_viewMode == PropertyViewMode.ClassMode) { - return; - } + if (m_state == null || m_prop == null) + { + return; + } - m_state.Properties.Remove(m_prop); - if (OnPropertyRemoved != null) + m_state.Properties.Remove(m_prop); + if (OnPropertyRemoved != null) + { + OnPropertyRemoved(m_prop); + } + propertyView.Refresh(); + } + else if (m_viewMode == PropertyViewMode.TimingFunction) + { + var func = (TimingFunction)propertyView.SelectedObject; + if(func != null) + { + m_style.TimingFunctions.Remove(func); + if (OnPropertyRemoved != null) + { + OnPropertyRemoved(m_prop); + } + propertyView.Refresh(); + } + } + else if (m_viewMode == PropertyViewMode.AnimationMode) { - OnPropertyRemoved(m_prop); + var anim = (AnimationTypeDescriptor)propertyView.SelectedObject; + if(anim != null && m_SelectedAnimationPart == null) + { + //remove all animations + foreach (var item in anim.Animations) + { + m_style.Animations.Remove(item); + } + } + if (m_SelectedAnimationPart != null) + { + m_style.Animations.Remove(m_SelectedAnimationPart); + } + + if (OnPropertyRemoved != null) + { + if (m_prop != null) + OnPropertyRemoved(m_prop); + else if (m_SelectedAnimationPart != null) + OnPropertyRemoved(m_SelectedAnimationPart); + } + propertyView.Refresh(); } - propertyView.Refresh(); } private void OnPropertySelected(object sender, SelectedGridItemChangedEventArgs e) { - if (m_viewMode != PropertyViewMode.ClassMode) - return; - const int CTX_ADD = 0; - const int CTX_REM = 1; + if (m_viewMode == PropertyViewMode.ClassMode) + { + const int CTX_ADD = 0; + const int CTX_REM = 1; - bool haveSelection = e.NewSelection != null; - propViewContextMenu.Items[CTX_ADD].Enabled = haveSelection; - propViewContextMenu.Items[CTX_REM].Enabled = haveSelection; - if (!haveSelection) - return; + bool haveSelection = e.NewSelection != null; + propViewContextMenu.Items[CTX_ADD].Enabled = haveSelection; + propViewContextMenu.Items[CTX_REM].Enabled = haveSelection; + if (!haveSelection) + return; - var propDesc = e.NewSelection.PropertyDescriptor as StylePropertyDescriptor; - if (propDesc != null) - { - propViewContextMenu.Items[CTX_ADD].Text = "Add Property to [" + propDesc.Category + "]"; - propViewContextMenu.Items[CTX_REM].Text = "Remove " + propDesc.Name; + var propDesc = e.NewSelection.PropertyDescriptor as StylePropertyDescriptor; + if (propDesc != null) + { + propViewContextMenu.Items[CTX_ADD].Text = "Add Property to [" + propDesc.Category + "]"; + propViewContextMenu.Items[CTX_REM].Text = "Remove " + propDesc.Name; - m_state = propDesc.StyleState; - m_prop = propDesc.StyleProperty; - return; - } + m_state = propDesc.StyleState; + m_prop = propDesc.StyleProperty; + return; + } - var dummyDesc = e.NewSelection.PropertyDescriptor as PlaceHolderPropertyDescriptor; - if (dummyDesc != null) - { - propViewContextMenu.Items[CTX_ADD].Enabled = true; - propViewContextMenu.Items[CTX_ADD].Text = "Add Property to [" + dummyDesc.Category + "]"; - propViewContextMenu.Items[CTX_REM].Enabled = false; - propViewContextMenu.Items[CTX_REM].Text = "Remove"; - m_state = dummyDesc.StyleState; - return; - } + var dummyDesc = e.NewSelection.PropertyDescriptor as PlaceHolderPropertyDescriptor; + if (dummyDesc != null) + { + propViewContextMenu.Items[CTX_ADD].Enabled = true; + propViewContextMenu.Items[CTX_ADD].Text = "Add Property to [" + dummyDesc.Category + "]"; + propViewContextMenu.Items[CTX_REM].Enabled = false; + propViewContextMenu.Items[CTX_REM].Text = "Remove"; + m_state = dummyDesc.StyleState; + return; + } - if (e.NewSelection.GridItemType == GridItemType.Category) - { - OnPropertySelected(sender, new SelectedGridItemChangedEventArgs(null, e.NewSelection.GridItems[0])); // select child - return; - } + if (e.NewSelection.GridItemType == GridItemType.Category) + { + OnPropertySelected(sender, new SelectedGridItemChangedEventArgs(null, e.NewSelection.GridItems[0])); // select child + return; + } - if (e.NewSelection.GridItemType == GridItemType.Property) + if (e.NewSelection.GridItemType == GridItemType.Property) + { + OnPropertySelected(sender, new SelectedGridItemChangedEventArgs(null, e.NewSelection.Parent)); // select parent + return; + } + } + else if (m_viewMode == PropertyViewMode.AnimationMode) { - OnPropertySelected(sender, new SelectedGridItemChangedEventArgs(null, e.NewSelection.Parent)); // select parent - return; + if (e.NewSelection == null) + return; + + var prop = e.NewSelection.PropertyDescriptor as AnimationPropertyDescriptior; + if(prop != null) + { + Debug.WriteLine("selected property descriptor"); + } + + if (e.NewSelection.GridItemType == GridItemType.Category) + { + m_SelectedAnimationPart = (e.NewSelection.GridItems[0].PropertyDescriptor as AnimationPropertyDescriptior).m_animation; + } + + if (e.NewSelection.GridItemType == GridItemType.Property) + { + Debug.WriteLine("selected prop " + e.NewSelection.Parent.Label); + } } } } diff --git a/msstyleEditorSharp/PropView/TypeDescriptors.cs b/msstyleEditorSharp/PropView/TypeDescriptors.cs index decb69a..1e1d582 100644 --- a/msstyleEditorSharp/PropView/TypeDescriptors.cs +++ b/msstyleEditorSharp/PropView/TypeDescriptors.cs @@ -391,7 +391,7 @@ public class AnimationPropertyDescriptior : PropertyDescriptor public override Type PropertyType => m_fi.PropertyType; private System.Reflection.PropertyInfo m_fi; - private Animation m_animation; + public Animation m_animation; private string m_category; public override string Category => m_category; From 0b8fb43e107ac7bd832b15429fcb31ffa12dee5e Mon Sep 17 00:00:00 2001 From: Misha Date: Sat, 7 Oct 2023 12:23:28 -0400 Subject: [PATCH 5/6] fix animation adding --- libmsstyle/Animation.cs | 8 ++++++-- msstyleEditorSharp/Dialogs/MainWindow.cs | 3 ++- msstyleEditorSharp/Dialogs/PropertyView.cs | 24 ++++++++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/libmsstyle/Animation.cs b/libmsstyle/Animation.cs index 4fba0a7..7a92056 100644 --- a/libmsstyle/Animation.cs +++ b/libmsstyle/Animation.cs @@ -67,6 +67,7 @@ public Animation(PropertyHeader header, int part, int state) Header = header; Header.stateID = state; Header.partID = part; + CalculateTotalSize(); } int GetPaddingForSize(int size) @@ -76,7 +77,7 @@ int GetPaddingForSize(int size) return ((size + 39) & -8) - sizeOfRecordHeader - size; } - public void Write(BinaryWriter bw) + private void CalculateTotalSize() { // Update the total size int total_size = 56; @@ -84,9 +85,12 @@ public void Write(BinaryWriter bw) { total_size += item.StructureSize + GetPaddingForSize(item.StructureSize); } - Header.sizeInBytes = total_size; + } + public void Write(BinaryWriter bw) + { + CalculateTotalSize(); bw.Write(Header.Serialize()); WriteData(bw); } diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index 47316f3..d21515d 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -710,7 +710,8 @@ private void OnPropertyAdded(object prop) if (prop is Animation animation) { m_selectedAnimation = new AnimationTypeDescriptor(animation); - m_propertyView.SetAnimation(m_style, m_selectedAnimation); + m_classView.Refresh(); + m_propertyView.SetStylePart(null, null, null); } } diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index 269b482..2453f27 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -85,10 +85,30 @@ private void OnPropertyAdd(object sender, EventArgs e) { var dlg2 = new NewAnimationDialog(); //typeid is the same for all animations - var anim = dlg2.ShowDialog(new PropertyHeader(20000, m_style.Animations[0].Header.typeID) { classID = m_class.ClassId}); + var anim = dlg2.ShowDialog(new PropertyHeader((int)IDENTIFIER.ANIMATION, m_style.Animations[0].Header.typeID) { classID = m_class.ClassId}); if (anim != null) { - m_style.Animations.Add(anim); + //check if there are any animations with same part id. it is important that all animations are sorted correctly + int idx = 0; + int latest_idx = -1; + foreach (var item in m_style.Animations) + { + if(item.Header.partID == anim.Header.partID) + { + latest_idx = idx; + } + idx++; + } + + if (latest_idx == -1) + { + m_style.Animations.Add(anim); + } + else + { + m_style.Animations.Insert(latest_idx + 1, anim); + } + if (OnPropertyAdded != null) { OnPropertyAdded(anim); From 06a53f0f00f24980eeb488af4376aa8104e7495d Mon Sep 17 00:00:00 2001 From: Misha Date: Sun, 8 Oct 2023 16:41:57 -0400 Subject: [PATCH 6/6] Add support for adding/removing timing functions --- libmsstyle/TimingFunction.cs | 6 ++++ libmsstyle/VisualStyle.cs | 2 +- msstyleEditorSharp/Dialogs/MainWindow.cs | 7 ++++ ...alog.Designer.cs => NewDialog.Designer.cs} | 2 +- .../{NewAnimationDialog.cs => NewDialog.cs} | 32 +++++++++++++++---- ...NewAnimationDialog.resx => NewDialog.resx} | 0 msstyleEditorSharp/Dialogs/PropertyView.cs | 18 +++++++++-- msstyleEditorSharp/msstyleEditorSharp.csproj | 10 +++--- 8 files changed, 62 insertions(+), 15 deletions(-) rename msstyleEditorSharp/Dialogs/{NewAnimationDialog.Designer.cs => NewDialog.Designer.cs} (99%) rename msstyleEditorSharp/Dialogs/{NewAnimationDialog.cs => NewDialog.cs} (55%) rename msstyleEditorSharp/Dialogs/{NewAnimationDialog.resx => NewDialog.resx} (100%) diff --git a/libmsstyle/TimingFunction.cs b/libmsstyle/TimingFunction.cs index a0b4795..b119f86 100644 --- a/libmsstyle/TimingFunction.cs +++ b/libmsstyle/TimingFunction.cs @@ -32,6 +32,12 @@ public TimingFunction(byte[] data, int start, PropertyHeader header) throw new Exception("Unknown timing function type: " + Type); } } + public TimingFunction(PropertyHeader header, int partid) + { + CubicBezier = new CubicBezierTimingFunction(); + Header = header; + Header.partID = partid; + } public void Write(BinaryWriter bw) { if (Type == TimingFunctionType.Undefined) diff --git a/libmsstyle/VisualStyle.cs b/libmsstyle/VisualStyle.cs index fb6aa64..191e8c5 100644 --- a/libmsstyle/VisualStyle.cs +++ b/libmsstyle/VisualStyle.cs @@ -319,7 +319,7 @@ private bool SaveAMap(IntPtr moduleHandle, IntPtr updateHandle) MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); - + m_timingFunctions.OrderBy(t => t.Header.partID); foreach (var item in m_timingFunctions) { item.Write(bw); diff --git a/msstyleEditorSharp/Dialogs/MainWindow.cs b/msstyleEditorSharp/Dialogs/MainWindow.cs index d21515d..ed8dc98 100644 --- a/msstyleEditorSharp/Dialogs/MainWindow.cs +++ b/msstyleEditorSharp/Dialogs/MainWindow.cs @@ -713,6 +713,13 @@ private void OnPropertyAdded(object prop) m_classView.Refresh(); m_propertyView.SetStylePart(null, null, null); } + + if (prop is TimingFunction timingFunc) + { + m_selectedTimingFunction = timingFunc; + m_classView.Refresh(); + m_propertyView.SetStylePart(null, null, null); + } } private void OnPropertyRemove(object sender, EventArgs e) diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs b/msstyleEditorSharp/Dialogs/NewDialog.Designer.cs similarity index 99% rename from msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs rename to msstyleEditorSharp/Dialogs/NewDialog.Designer.cs index 46454cc..9875705 100644 --- a/msstyleEditorSharp/Dialogs/NewAnimationDialog.Designer.cs +++ b/msstyleEditorSharp/Dialogs/NewDialog.Designer.cs @@ -1,6 +1,6 @@ namespace msstyleEditor.Dialogs { - partial class NewAnimationDialog + partial class NewDialog { /// /// Required designer variable. diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs b/msstyleEditorSharp/Dialogs/NewDialog.cs similarity index 55% rename from msstyleEditorSharp/Dialogs/NewAnimationDialog.cs rename to msstyleEditorSharp/Dialogs/NewDialog.cs index 8055f4e..4f5c5ba 100644 --- a/msstyleEditorSharp/Dialogs/NewAnimationDialog.cs +++ b/msstyleEditorSharp/Dialogs/NewDialog.cs @@ -11,18 +11,19 @@ namespace msstyleEditor.Dialogs { - public partial class NewAnimationDialog : Form + public partial class NewDialog : Form { public int PartID { get; private set; } public int StateID { get; private set; } - public NewAnimationDialog() + private bool HasState { get; set; } + public NewDialog() { InitializeComponent(); } private void btnCreate_Click(object sender, EventArgs e) { - if(!int.TryParse(txtPartId.Text, out int PartID)) + if (!int.TryParse(txtPartId.Text, out int PartID)) { MessageBox.Show("Part ID must be a number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -30,7 +31,7 @@ private void btnCreate_Click(object sender, EventArgs e) this.PartID = PartID; - if (!int.TryParse(txtStateId.Text, out int StateID)) + if (!int.TryParse(txtStateId.Text, out int StateID) && HasState) { MessageBox.Show("State ID must be a number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -41,9 +42,12 @@ private void btnCreate_Click(object sender, EventArgs e) DialogResult = DialogResult.OK; } - public new Animation ShowDialog(PropertyHeader header) + public Animation ShowDialogAnimation(PropertyHeader header) { - if(base.ShowDialog() == DialogResult.OK) + Text = "New animation"; + HasState = true; + txtStateId.Enabled = true; + if (base.ShowDialog() == DialogResult.OK) { return new Animation(header, PartID, StateID); } @@ -52,5 +56,21 @@ private void btnCreate_Click(object sender, EventArgs e) return null; } } + + public TimingFunction ShowDialogTimingFunction(PropertyHeader header) + { + Text = "New timing function"; + HasState = false; + txtStateId.Enabled = false; + label2.Enabled = false; + if (base.ShowDialog() == DialogResult.OK) + { + return new TimingFunction(header, PartID); + } + else + { + return null; + } + } } } diff --git a/msstyleEditorSharp/Dialogs/NewAnimationDialog.resx b/msstyleEditorSharp/Dialogs/NewDialog.resx similarity index 100% rename from msstyleEditorSharp/Dialogs/NewAnimationDialog.resx rename to msstyleEditorSharp/Dialogs/NewDialog.resx diff --git a/msstyleEditorSharp/Dialogs/PropertyView.cs b/msstyleEditorSharp/Dialogs/PropertyView.cs index 2453f27..b340ae5 100644 --- a/msstyleEditorSharp/Dialogs/PropertyView.cs +++ b/msstyleEditorSharp/Dialogs/PropertyView.cs @@ -83,9 +83,9 @@ private void OnPropertyAdd(object sender, EventArgs e) { if (m_class.ClassName == "animations") { - var dlg2 = new NewAnimationDialog(); + var dlg2 = new NewDialog(); //typeid is the same for all animations - var anim = dlg2.ShowDialog(new PropertyHeader((int)IDENTIFIER.ANIMATION, m_style.Animations[0].Header.typeID) { classID = m_class.ClassId}); + var anim = dlg2.ShowDialogAnimation(new PropertyHeader((int)IDENTIFIER.ANIMATION, m_style.Animations[0].Header.typeID) { classID = m_class.ClassId}); if (anim != null) { //check if there are any animations with same part id. it is important that all animations are sorted correctly @@ -117,6 +117,20 @@ private void OnPropertyAdd(object sender, EventArgs e) } return; } + else if (m_class.ClassName == "timingfunction") + { + var dlg2 = new NewDialog(); + var timingfunc = dlg2.ShowDialogTimingFunction(new PropertyHeader((int)IDENTIFIER.TIMINGFUNCTION, m_style.TimingFunctions[0].Header.typeID) { classID = m_class.ClassId }); + if(timingfunc != null) + m_style.TimingFunctions.Add(timingfunc); + + if (OnPropertyAdded != null) + { + OnPropertyAdded(timingfunc); + } + propertyView.Refresh(); + return; + } } if(m_style == null || m_class == null diff --git a/msstyleEditorSharp/msstyleEditorSharp.csproj b/msstyleEditorSharp/msstyleEditorSharp.csproj index 11d303a..7080b72 100644 --- a/msstyleEditorSharp/msstyleEditorSharp.csproj +++ b/msstyleEditorSharp/msstyleEditorSharp.csproj @@ -133,11 +133,11 @@ LicenseDialog.cs - + Form - - NewAnimationDialog.cs + + NewDialog.cs Form @@ -222,8 +222,8 @@ MainWindow.cs Designer - - NewAnimationDialog.cs + + NewDialog.cs PropertyView.cs