aboutsummaryrefslogtreecommitdiffstatsci
path: root/Samples
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2022-07-17 20:26:28 +0200
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>2022-07-17 20:26:28 +0200
commit9d786ab096ed36ea384e03ee5cea498790e31eec (patch)
treeadee54b5b90a35238d5794e9ffd3ebcf65798a06 /Samples
parent57daad000aa31c7bcfa1f76b90d40da5a21da041 (diff)
wip
Diffstat (limited to 'Samples')
-rw-r--r--Samples/AnimTest/AnimTest.csproj11
-rw-r--r--Samples/AnimTest/Animation/AngleAnimation.cs19
-rw-r--r--Samples/AnimTest/Animation/Animation.cs155
-rw-r--r--Samples/AnimTest/Animation/AnimationTemplate.cs110
-rw-r--r--Samples/AnimTest/Animation/BezierPath.cs34
-rw-r--r--Samples/AnimTest/Animation/FloatAnimation.cs83
-rw-r--r--Samples/AnimTest/Animation/FloatAnimation2.cs60
-rw-r--r--Samples/AnimTest/Animation/MathHelper.cs16
-rw-r--r--Samples/AnimTest/Animation/Path.cs51
-rw-r--r--Samples/AnimTest/Animation/PathAnimation.cs53
-rw-r--r--Samples/AnimTest/Animation/ShakeAnimation.cs60
-rw-r--r--Samples/AnimTest/MiscUtil/ExpressionUtil.cs99
-rw-r--r--Samples/AnimTest/MiscUtil/NullOp.cs59
-rw-r--r--Samples/AnimTest/MiscUtil/Operator.cs449
-rw-r--r--Samples/AnimTest/main.cs28
-rw-r--r--Samples/AnimTest/ui/anim.crow10
-rw-r--r--Samples/AnimTest/ui/background.crow4
-rw-r--r--Samples/AnimTest/ui/background.jpgbin0 -> 89291 bytes
-rw-r--r--Samples/BasicTests/BasicTests.cs14
-rw-r--r--Samples/HelloWorld/main.cs1
-rw-r--r--Samples/HelloWorld/ui/helloworld.crow9
-rw-r--r--Samples/ShowCase/ShowCase.cs37
-rw-r--r--Samples/ShowCase/ui/showcase.crow10
-rw-r--r--Samples/common/ui/Interfaces/Experimental/svg.crow2
-rw-r--r--Samples/common/ui/Interfaces/TemplatedContainer/buttons.crow62
25 files changed, 1422 insertions, 14 deletions
diff --git a/Samples/AnimTest/AnimTest.csproj b/Samples/AnimTest/AnimTest.csproj
new file mode 100644
index 00000000..178d4537
--- /dev/null
+++ b/Samples/AnimTest/AnimTest.csproj
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netcoreapp3.1</TargetFramework>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Crow" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Samples/AnimTest/Animation/AngleAnimation.cs b/Samples/AnimTest/Animation/AngleAnimation.cs
new file mode 100644
index 00000000..02faef76
--- /dev/null
+++ b/Samples/AnimTest/Animation/AngleAnimation.cs
@@ -0,0 +1,19 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace vke
+{
+ public class AngleAnimation : FloatAnimation2
+ {
+ #region CTOR
+ public AngleAnimation(Object instance, string PropertyName, float Target, int stepCount = 20) :
+ base (instance,PropertyName,MathHelper.NormalizeAngle(Target),stepCount) {
+ initialValue = MathHelper.NormalizeAngle (initialValue);
+ }
+ #endregion
+ }
+}
+
diff --git a/Samples/AnimTest/Animation/Animation.cs b/Samples/AnimTest/Animation/Animation.cs
new file mode 100644
index 00000000..6ca7af8c
--- /dev/null
+++ b/Samples/AnimTest/Animation/Animation.cs
@@ -0,0 +1,155 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace vke
+{
+ public delegate void AnimationEventHandler(Animation a);
+
+ public delegate float GetterDelegate();
+ public delegate void SetterDelegate(float value);
+
+ public class Animation
+ {
+ public event AnimationEventHandler AnimationFinished;
+
+ public static Random random = new Random ();
+ public static int DelayMs = 0;
+
+ protected GetterDelegate getValue;
+ protected SetterDelegate setValue;
+
+ public string propertyName;
+
+ protected Stopwatch timer = new Stopwatch();
+ protected int delayStartMs = 0;
+ /// <summary>
+ /// Delay before firing ZnimationFinished event.
+ /// </summary>
+ protected int delayFinishMs = 0;
+ public static List<Animation> AnimationList = new List<Animation>();
+ public static bool HasAnimations => AnimationList.Count > 0;
+ //public FieldInfo member;
+ public Object AnimatedInstance;
+
+ #region CTOR
+ public Animation (){}
+ public Animation(Object instance, string _propertyName)
+ {
+ propertyName = _propertyName;
+ AnimatedInstance = instance;
+ PropertyInfo pi = instance.GetType().GetProperty(propertyName);
+ try {
+ getValue = (GetterDelegate)Delegate.CreateDelegate(typeof(GetterDelegate), instance, pi.GetGetMethod());
+ setValue = (SetterDelegate)Delegate.CreateDelegate(typeof(SetterDelegate), instance, pi.GetSetMethod());
+ } catch (Exception ex) {
+ Debug.WriteLine (ex.ToString ());
+ }
+ }
+ #endregion
+
+ public static void StartAnimation(Animation a, int delayMs = 0, AnimationEventHandler OnEnd = null)
+ {
+ lock (AnimationList) {
+ Animation aa = null;
+ if (Animation.GetAnimation (a.AnimatedInstance, a.propertyName, ref aa)) {
+ aa.CancelAnimation ();
+ }
+
+ //a.AnimationFinished += onAnimationFinished;
+
+ a.AnimationFinished += OnEnd;
+ a.delayStartMs = delayMs + DelayMs;
+
+
+ if (a.delayStartMs > 0)
+ a.timer.Start ();
+
+ AnimationList.Add (a);
+ }
+
+ }
+
+ static Stack<Animation> anims = new Stack<Animation>();
+ static int frame = 0;
+ public static void ProcessAnimations()
+ {
+ frame++;
+
+// #region FLYING anim
+// if (frame % 20 == 0){
+// foreach (Player p in MagicEngine.CurrentEngine.Players) {
+// foreach (CardInstance c in p.InPlay.Cards.Where(ci => ci.HasAbility(AbilityEnum.Flying) && ci.z < 0.4f)) {
+//
+// }
+// }
+// }
+// #endregion
+ //Stopwatch animationTime = new Stopwatch();
+ //animationTime.Start();
+
+ const int maxAnim = 200000;
+ int count = 0;
+
+
+ lock (AnimationList) {
+ if (anims.Count == 0)
+ anims = new Stack<Animation> (AnimationList);
+ }
+
+ while (anims.Count > 0 && count < maxAnim) {
+ Animation a = anims.Pop ();
+ if (a == null)
+ continue;
+ if (a.timer.IsRunning) {
+ if (a.timer.ElapsedMilliseconds > a.delayStartMs)
+ a.timer.Stop ();
+ else
+ continue;
+ }
+
+ a.Process ();
+ count++;
+ }
+
+ //animationTime.Stop();
+ //Debug.WriteLine("animation: {0} ticks \t {1} ms ", animationTime.ElapsedTicks,animationTime.ElapsedMilliseconds);
+ }
+ public static bool GetAnimation(object instance, string PropertyName, ref Animation a)
+ {
+ for (int i = 0; i < AnimationList.Count; i++) {
+ Animation anim = AnimationList [i];
+ if (anim == null) {
+ continue;
+ }
+ if (anim.AnimatedInstance == instance && anim.propertyName == PropertyName) {
+ a = anim;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ public virtual void Process () {}
+ public void CancelAnimation()
+ {
+ //Debug.WriteLine("Cancel anim: " + this.ToString());
+ AnimationList.Remove(this);
+ }
+ public void RaiseAnimationFinishedEvent()
+ {
+ if (AnimationFinished != null)
+ AnimationFinished (this);
+ }
+
+ public static void onAnimationFinished(Animation a)
+ {
+ Debug.WriteLine ("\t\tAnimation finished: " + a.ToString ());
+ }
+ }
+}
diff --git a/Samples/AnimTest/Animation/AnimationTemplate.cs b/Samples/AnimTest/Animation/AnimationTemplate.cs
new file mode 100644
index 00000000..d5c784c3
--- /dev/null
+++ b/Samples/AnimTest/Animation/AnimationTemplate.cs
@@ -0,0 +1,110 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using MiscUtil;
+using System.Reflection;
+
+namespace vke
+{
+ public class Animation<T> : Animation
+ {
+ public delegate T GetterDelegate();
+ public delegate void SetterDelegate(T value);
+
+ public T TargetValue;
+ T initialValue;
+ T zero;
+ public T Step;
+ public bool Cycle;
+
+ protected GetterDelegate getValue;
+ protected SetterDelegate setValue;
+
+ #region CTOR
+ public Animation(Object instance, string _propertyName)
+ {
+ propertyName = _propertyName;
+ AnimatedInstance = instance;
+ PropertyInfo pi = instance.GetType().GetProperty(propertyName);
+ getValue = (GetterDelegate)Delegate.CreateDelegate(typeof(GetterDelegate), instance, pi.GetGetMethod());
+ setValue = (SetterDelegate)Delegate.CreateDelegate(typeof(SetterDelegate), instance, pi.GetSetMethod());
+ }
+ public Animation(Object instance, string _propertyName, T Target, T step)
+ {
+ propertyName = _propertyName;
+ AnimatedInstance = instance;
+ PropertyInfo pi = instance.GetType().GetProperty(propertyName);
+ getValue = (GetterDelegate)Delegate.CreateDelegate(typeof(GetterDelegate), instance, pi.GetGetMethod());
+ setValue = (SetterDelegate)Delegate.CreateDelegate(typeof(SetterDelegate), instance, pi.GetSetMethod());
+
+ TargetValue = Target;
+
+ T value = getValue();
+ initialValue = value;
+ Type t = typeof(T);
+
+ if (t.IsPrimitive) {
+ Step = (T)Convert.ChangeType (step, t);
+ zero = (T)Convert.ChangeType (0, t);
+ }else {
+ Step = (T)Activator.CreateInstance (typeof(T), new Object[] { step });
+ zero = (T)Activator.CreateInstance (typeof(T), 0f);
+ }
+ T test = (T)Operator.SubtractAlternative (value, TargetValue);
+
+ if (Operator.LessThan(test, zero))
+ {
+ if (Operator.LessThan (Step, zero))
+ Step = Operator.Negate (Step);
+ }
+ else if (Operator.GreaterThan(Step, zero))
+ Step = Operator.Negate (Step);
+ }
+ #endregion
+
+ public override void Process()
+ {
+ T value = getValue();
+
+ //Debug.WriteLine ("Anim: {0} <= {1}", value, this.ToString ());
+
+ if (Operator.GreaterThan(Step, zero))
+ {
+ value = Operator.Add (value, Step);
+ setValue(value);
+ //Debug.WriteLine(value);
+ if (Operator.GreaterThan(Operator.Subtract(TargetValue, value), zero))
+ return;
+ }
+ else
+ {
+ value = Operator.Add (value, Step);
+ setValue(value);
+
+ if (Operator.LessThan(Operator.Subtract(TargetValue, value), zero))
+ return;
+ }
+
+ if (Cycle) {
+ Step = Operator.Negate (Step);
+ TargetValue = initialValue;
+ Cycle = false;
+ return;
+ }
+
+ setValue(TargetValue);
+ AnimationList.Remove(this);
+
+ RaiseAnimationFinishedEvent ();
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}:->{1}:{2}",base.ToString(),TargetValue,Step);
+ }
+ }
+
+}
+
diff --git a/Samples/AnimTest/Animation/BezierPath.cs b/Samples/AnimTest/Animation/BezierPath.cs
new file mode 100644
index 00000000..a3126e3e
--- /dev/null
+++ b/Samples/AnimTest/Animation/BezierPath.cs
@@ -0,0 +1,34 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Numerics;
+
+namespace vke
+{
+ public class BezierPath : Path
+ {
+ public Vector3 ControlPointStart;
+ public Vector3 ControlPointEnd;
+
+ public BezierPath (Vector3 startPos, Vector3 controlPointStart,
+ Vector3 controlPointEnd, Vector3 endPos)
+ :base(startPos, endPos)
+ {
+ ControlPointStart = controlPointStart;
+ ControlPointEnd = controlPointEnd;
+ }
+ public BezierPath (Vector3 startPos, Vector3 endPos, Vector3 vUp)
+ :base(startPos, endPos)
+ {
+ ControlPointStart = startPos + vUp;
+ ControlPointEnd = endPos + vUp;
+ }
+ public override Vector3 GetStep (float pos)
+ {
+ return Path.CalculateBezierPoint (pos, Start, ControlPointStart, ControlPointEnd, End);
+ }
+ }
+}
+
diff --git a/Samples/AnimTest/Animation/FloatAnimation.cs b/Samples/AnimTest/Animation/FloatAnimation.cs
new file mode 100644
index 00000000..a7e4bf7c
--- /dev/null
+++ b/Samples/AnimTest/Animation/FloatAnimation.cs
@@ -0,0 +1,83 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace vke
+{
+ public class FloatAnimation : Animation
+ {
+
+ public float TargetValue;
+ float initialValue;
+ public float Step;
+ public bool Cycle;
+
+ #region CTOR
+ public FloatAnimation(Object instance, string _propertyName, float Target, float step = 0.2f)
+ : base(instance, _propertyName)
+ {
+
+ TargetValue = Target;
+
+ float value = getValue();
+ initialValue = value;
+
+ Step = step;
+
+ if (value < TargetValue)
+ {
+ if (Step < 0)
+ Step = -Step;
+ }
+ else if (Step > 0)
+ Step = -Step;
+ }
+ #endregion
+
+ public override void Process()
+ {
+ float value = getValue();
+
+ //Debug.WriteLine ("Anim: {0} <= {1}", value, this.ToString ());
+
+ if (Step > 0f)
+ {
+ value += Step;
+ setValue(value);
+ //Debug.WriteLine(value);
+ if (TargetValue > value)
+ return;
+ }
+ else
+ {
+ value += Step;
+ setValue(value);
+
+ if (TargetValue < value)
+ return;
+ }
+
+ if (Cycle) {
+ Step = -Step;
+ TargetValue = initialValue;
+ Cycle = false;
+ return;
+ }
+
+ setValue(TargetValue);
+ lock(AnimationList)
+ AnimationList.Remove(this);
+
+ RaiseAnimationFinishedEvent ();
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}:->{1}:{2}",base.ToString(),TargetValue,Step);
+ }
+ }
+
+}
+
diff --git a/Samples/AnimTest/Animation/FloatAnimation2.cs b/Samples/AnimTest/Animation/FloatAnimation2.cs
new file mode 100644
index 00000000..1d5c9193
--- /dev/null
+++ b/Samples/AnimTest/Animation/FloatAnimation2.cs
@@ -0,0 +1,60 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace vke
+{
+ public class FloatAnimation2 : Animation
+ {
+
+ public float TargetValue;
+ protected float initialValue;
+ int stepCount, currentStep;
+
+ #region CTOR
+ public FloatAnimation2(Object instance, string _propertyName, float Target, int _stepCount = 20)
+ : base(instance, _propertyName)
+ {
+
+ TargetValue = Target;
+
+ float value = getValue();
+ initialValue = value;
+
+ stepCount = _stepCount;
+ }
+ #endregion
+
+ bool smooth = true;
+
+ float smoothedStep (float step) => (-MathF.Cos (step * MathF.PI) + 1)/2.0f;
+
+ public override void Process()
+ {
+
+ currentStep++;
+
+ float t = (float)currentStep / (float)stepCount;
+ if (smooth)
+ t = smoothedStep (t);
+
+ setValue (initialValue + t * (TargetValue - initialValue));
+
+ if (currentStep < stepCount)
+ return;
+
+ setValue(TargetValue);
+ AnimationList.Remove(this);
+ RaiseAnimationFinishedEvent ();
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}:->{1}:{2}",base.ToString(),TargetValue,stepCount);
+ }
+ }
+
+}
+
diff --git a/Samples/AnimTest/Animation/MathHelper.cs b/Samples/AnimTest/Animation/MathHelper.cs
new file mode 100644
index 00000000..35a3009f
--- /dev/null
+++ b/Samples/AnimTest/Animation/MathHelper.cs
@@ -0,0 +1,16 @@
+// Copyright (c) 2019-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+namespace vke {
+ public static class MathHelper {
+ public const float Pi = (float)Math.PI;
+ public const float TwoPi = (float)Math.PI * 2;
+ public static float NormalizeAngle (float a) {
+ float tmp = a % MathHelper.TwoPi;
+ if (tmp < 0)
+ tmp += MathHelper.TwoPi;
+ return tmp;
+ }
+ }
+}
diff --git a/Samples/AnimTest/Animation/Path.cs b/Samples/AnimTest/Animation/Path.cs
new file mode 100644
index 00000000..1f04e090
--- /dev/null
+++ b/Samples/AnimTest/Animation/Path.cs
@@ -0,0 +1,51 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Numerics;
+
+namespace vke {
+ public class Path
+ {
+ public Vector3 Start;
+ public Vector3 End;
+
+ float length;
+ Vector3 vDir;
+
+ public Path(Vector3 startPos, Vector3 endPos){
+ Start = startPos;
+ End = endPos;
+ initialComputations ();
+ }
+ protected void initialComputations(){
+ Vector3 vPath = End - Start;
+ vDir = Vector3.Normalize (vPath);
+ length = vPath.Length();
+ }
+ /// <summary>
+ /// Get single step on the path
+ /// </summary>
+ /// <returns>return position on the path</returns>
+ /// <param name="pos">Position expressed as percentage of total length</param>
+ public virtual Vector3 GetStep(float pos){
+ return Start + vDir * length * pos;
+ }
+
+ public static Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
+ {
+ float u = 1 - t;
+ float tt = t * t;
+ float uu = u * u;
+ float uuu = uu * u;
+ float ttt = tt * t;
+
+ Vector3 p = uuu * p0;
+ p += 3 * uu * t * p1;
+ p += 3 * u * tt * p2;
+ p += ttt * p3;
+
+ return p;
+ }
+ }
+
+}
diff --git a/Samples/AnimTest/Animation/PathAnimation.cs b/Samples/AnimTest/Animation/PathAnimation.cs
new file mode 100644
index 00000000..54c30e9a
--- /dev/null
+++ b/Samples/AnimTest/Animation/PathAnimation.cs
@@ -0,0 +1,53 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Numerics;
+
+namespace vke
+{
+ public class PathAnimation : Animation<Vector3>
+ {
+ Path path;
+ int stepCount, currentStep;
+
+ #region CTOR
+ public PathAnimation(Object instance, string _propertyName, Path _path, int _stepCount = 20)
+ : base(instance, _propertyName)
+ {
+ path = _path;
+ stepCount = _stepCount;
+ }
+
+ #endregion
+
+ bool smooth = true;
+
+ float smoothedStep (float step) => (-MathF.Cos (step * MathF.PI) + 1)/2.0f;
+
+ public override void Process()
+ {
+ currentStep++;
+
+ float t = (float)currentStep / (float)stepCount;
+ if (smooth)
+ t = smoothedStep (t);
+
+ Vector3 pos = path.GetStep (t);
+ setValue(pos);
+
+ if (currentStep < stepCount)
+ return;
+
+ AnimationList.Remove(this);
+ RaiseAnimationFinishedEvent ();
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}:->{1}:{2}",base.ToString(),TargetValue,Step);
+ }
+ }
+}
+
diff --git a/Samples/AnimTest/Animation/ShakeAnimation.cs b/Samples/AnimTest/Animation/ShakeAnimation.cs
new file mode 100644
index 00000000..37a089bd
--- /dev/null
+++ b/Samples/AnimTest/Animation/ShakeAnimation.cs
@@ -0,0 +1,60 @@
+// Copyright (c) 2015-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace vke
+{
+ public class ShakeAnimation : Animation
+ {
+ const float stepMin = 0.001f, stepMax = 0.005f;
+ bool rising = true;
+
+ public float LowBound;
+ public float HighBound;
+
+ #region CTOR
+ public ShakeAnimation(
+ Object instance,
+ string _propertyName,
+ float lowBound, float highBound)
+ : base(instance, _propertyName)
+ {
+
+ LowBound = Math.Min (lowBound, highBound);
+ HighBound = Math.Max (lowBound, highBound);
+
+ float value = getValue ();
+
+ if (value > HighBound)
+ rising = false;
+ }
+ #endregion
+
+ public override void Process ()
+ {
+ float value = getValue ();
+ float step = stepMin + (float)random.NextDouble () * stepMax;
+
+ if (rising) {
+ value += step;
+ if (value > HighBound) {
+ value = HighBound;
+ rising = false;
+ }
+ } else {
+ value -= step;
+ if (value < LowBound) {
+ value = LowBound;
+ rising = true;
+ } else if (value > HighBound)
+ value -= step * 10f;
+ }
+ setValue (value);
+ }
+
+ }
+
+}
+
diff --git a/Samples/AnimTest/MiscUtil/ExpressionUtil.cs b/Samples/AnimTest/MiscUtil/ExpressionUtil.cs
new file mode 100644
index 00000000..8f9ca4e6
--- /dev/null
+++ b/Samples/AnimTest/MiscUtil/ExpressionUtil.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MiscUtil.Linq
+{
+ /// <summary>
+ /// General purpose Expression utilities
+ /// </summary>
+ public static class ExpressionUtil
+ {
+ /// <summary>
+ /// Create a function delegate representing a unary operation
+ /// </summary>
+ /// <typeparam name="TArg1">The parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TResult> CreateExpression<TArg1, TResult>(
+ Func<Expression, UnaryExpression> body)
+ {
+ ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp");
+ try
+ {
+ return Expression.Lambda<Func<TArg1, TResult>>(body(inp), inp).Compile();
+ }
+ catch (Exception ex)
+ {
+ string msg = ex.Message; // avoid capture of ex itself
+ return delegate { throw new InvalidOperationException(msg); };
+ }
+ }
+
+ /// <summary>
+ /// Create a function delegate representing a binary operation
+ /// </summary>
+ /// <typeparam name="TArg1">The first parameter type</typeparam>
+ /// <typeparam name="TArg2">The second parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>(
+ Func<Expression, Expression, BinaryExpression> body)
+ {
+ return CreateExpression<TArg1, TArg2, TResult>(body, false);
+ }
+
+ /// <summary>
+ /// Create a function delegate representing a binary operation
+ /// </summary>
+ /// <param name="castArgsToResultOnFailure">
+ /// If no matching operation is possible, attempt to convert
+ /// TArg1 and TArg2 to TResult for a match? For example, there is no
+ /// "decimal operator /(decimal, int)", but by converting TArg2 (int) to
+ /// TResult (decimal) a match is found.
+ /// </param>
+ /// <typeparam name="TArg1">The first parameter type</typeparam>
+ /// <typeparam name="TArg2">The second parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>(
+ Func<Expression, Expression, BinaryExpression> body, bool castArgsToResultOnFailure)
+ {
+ ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs");
+ ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs");
+ try
+ {
+ try
+ {
+ return Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, rhs), lhs, rhs).Compile();
+ }
+ catch (InvalidOperationException)
+ {
+ if (castArgsToResultOnFailure && !( // if we show retry
+ typeof(TArg1) == typeof(TResult) && // and the args aren't
+ typeof(TArg2) == typeof(TResult)))
+ { // already "TValue, TValue, TValue"...
+ // convert both lhs and rhs to TResult (as appropriate)
+ Expression castLhs = typeof(TArg1) == typeof(TResult) ?
+ (Expression)lhs :
+ (Expression)Expression.Convert(lhs, typeof(TResult));
+ Expression castRhs = typeof(TArg2) == typeof(TResult) ?
+ (Expression)rhs :
+ (Expression)Expression.Convert(rhs, typeof(TResult));
+
+ return Expression.Lambda<Func<TArg1, TArg2, TResult>>(
+ body(castLhs, castRhs), lhs, rhs).Compile();
+ }
+ else throw;
+ }
+ }
+ catch (Exception ex)
+ {
+ string msg = ex.Message; // avoid capture of ex itself
+ return delegate { throw new InvalidOperationException(msg); };
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Samples/AnimTest/MiscUtil/NullOp.cs b/Samples/AnimTest/MiscUtil/NullOp.cs
new file mode 100644
index 00000000..7bb8790a
--- /dev/null
+++ b/Samples/AnimTest/MiscUtil/NullOp.cs
@@ -0,0 +1,59 @@
+
+namespace MiscUtil
+{
+ interface INullOp<T>
+ {
+ bool HasValue(T value);
+ bool AddIfNotNull(ref T accumulator, T value);
+ }
+ sealed class StructNullOp<T>
+ : INullOp<T>, INullOp<T?>
+ where T : struct
+ {
+ public bool HasValue(T value)
+ {
+ return true;
+ }
+ public bool AddIfNotNull(ref T accumulator, T value)
+ {
+ accumulator = Operator<T>.Add(accumulator, value);
+ return true;
+ }
+ public bool HasValue(T? value)
+ {
+ return value.HasValue;
+ }
+ public bool AddIfNotNull(ref T? accumulator, T? value)
+ {
+ if (value.HasValue)
+ {
+ accumulator = accumulator.HasValue ?
+ Operator<T>.Add(
+ accumulator.GetValueOrDefault(),
+ value.GetValueOrDefault())
+ : value;
+ return true;
+ }
+ return false;
+ }
+ }
+ sealed class ClassNullOp<T>
+ : INullOp<T>
+ where T : class
+ {
+ public bool HasValue(T value)
+ {
+ return value != null;
+ }
+ public bool AddIfNotNull(ref T accumulator, T value)
+ {
+ if (value != null)
+ {
+ accumulator = accumulator == null ?
+ value : Operator<T>.Add(accumulator, value);
+ return true;
+ }
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/Samples/AnimTest/MiscUtil/Operator.cs b/Samples/AnimTest/MiscUtil/Operator.cs
new file mode 100644
index 00000000..ee1168cf
--- /dev/null
+++ b/Samples/AnimTest/MiscUtil/Operator.cs
@@ -0,0 +1,449 @@
+using System;
+using System.Linq.Expressions;
+using MiscUtil.Linq;
+
+namespace MiscUtil
+{
+ /// <summary>
+ /// The Operator class provides easy access to the standard operators
+ /// (addition, etc) for generic types, using type inference to simplify
+ /// usage.
+ /// </summary>
+ public static class Operator
+ {
+
+ /// <summary>
+ /// Indicates if the supplied value is non-null,
+ /// for reference-types or Nullable&lt;T&gt;
+ /// </summary>
+ /// <returns>True for non-null values, else false</returns>
+ public static bool HasValue<T>(T value)
+ {
+ return Operator<T>.NullOp.HasValue(value);
+ }
+ /// <summary>
+ /// Increments the accumulator only
+ /// if the value is non-null. If the accumulator
+ /// is null, then the accumulator is given the new
+ /// value; otherwise the accumulator and value
+ /// are added.
+ /// </summary>
+ /// <param name="accumulator">The current total to be incremented (can be null)</param>
+ /// <param name="value">The value to be tested and added to the accumulator</param>
+ /// <returns>True if the value is non-null, else false - i.e.
+ /// "has the accumulator been updated?"</returns>
+ public static bool AddIfNotNull<T>(ref T accumulator, T value)
+ {
+ return Operator<T>.NullOp.AddIfNotNull(ref accumulator, value);
+ }
+
+ /// <summary>
+ /// Evaluates unary negation (-) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Negate<T>(T value)
+ {
+ return Operator<T>.Negate(value);
+ }
+ /// <summary>
+ /// Evaluates bitwise not (~) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Not<T>(T value)
+ {
+ return Operator<T>.Not(value);
+ }
+ /// <summary>
+ /// Evaluates bitwise or (|) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Or<T>(T value1, T value2)
+ {
+ return Operator<T>.Or(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates bitwise and (&amp;) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T And<T>(T value1, T value2)
+ {
+ return Operator<T>.And(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates bitwise xor (^) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Xor<T>(T value1, T value2)
+ {
+ return Operator<T>.Xor(value1, value2);
+ }
+ /// <summary>
+ /// Performs a conversion between the given types; this will throw
+ /// an InvalidOperationException if the type T does not provide a suitable cast, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this cast.
+ /// </summary>
+ public static TTo Convert<TFrom, TTo>(TFrom value)
+ {
+ return Operator<TFrom, TTo>.Convert(value);
+ }
+ /// <summary>
+ /// Evaluates binary addition (+) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Add<T>(T value1, T value2)
+ {
+ return Operator<T>.Add(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary addition (+) for the given type(s); this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static TArg1 AddAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2)
+ {
+ return Operator<TArg2, TArg1>.Add(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary subtraction (-) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Subtract<T>(T value1, T value2)
+ {
+ return Operator<T>.Subtract(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary subtraction(-) for the given type(s); this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static TArg1 SubtractAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2)
+ {
+ return Operator<TArg2, TArg1>.Subtract(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary multiplication (*) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Multiply<T>(T value1, T value2)
+ {
+ return Operator<T>.Multiply(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary multiplication (*) for the given type(s); this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static TArg1 MultiplyAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2)
+ {
+ return Operator<TArg2, TArg1>.Multiply(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary division (/) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static T Divide<T>(T value1, T value2)
+ {
+ return Operator<T>.Divide(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary division (/) for the given type(s); this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static TArg1 DivideAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2)
+ {
+ return Operator<TArg2, TArg1>.Divide(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary equality (==) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool Equal<T>(T value1, T value2)
+ {
+ return Operator<T>.Equal(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary inequality (!=) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool NotEqual<T>(T value1, T value2)
+ {
+ return Operator<T>.NotEqual(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary greater-than (&gt;) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool GreaterThan<T>(T value1, T value2)
+ {
+ return Operator<T>.GreaterThan(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary less-than (&lt;) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool LessThan<T>(T value1, T value2)
+ {
+ return Operator<T>.LessThan(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary greater-than-on-eqauls (&gt;=) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool GreaterThanOrEqual<T>(T value1, T value2)
+ {
+ return Operator<T>.GreaterThanOrEqual(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates binary less-than-or-equal (&lt;=) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static bool LessThanOrEqual<T>(T value1, T value2)
+ {
+ return Operator<T>.LessThanOrEqual(value1, value2);
+ }
+ /// <summary>
+ /// Evaluates integer division (/) for the given type; this will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary><remarks>
+ /// This operation is particularly useful for computing averages and
+ /// similar aggregates.
+ /// </remarks>
+ public static T DivideInt32<T>(T value, int divisor)
+ {
+ return Operator<int,T>.Divide(value, divisor);
+ }
+ public static T Max<T>(T v1, T v2)
+ {
+ return Operator.GreaterThanOrEqual (v1, v2) ? v1 : v2;
+ }
+ public static T Min<T>(T v1, T v2)
+ {
+ return Operator.LessThanOrEqual (v1, v2) ? v1 : v2;
+ }
+ }
+ /// <summary>
+ /// Provides standard operators (such as addition) that operate over operands of
+ /// different types. For operators, the return type is assumed to match the first
+ /// operand.
+ /// </summary>
+ /// <seealso cref="Operator&lt;T&gt;"/>
+ /// <seealso cref="Operator"/>
+ public static class Operator<TValue, TResult>
+ {
+ private static readonly Func<TValue, TResult> convert;
+ /// <summary>
+ /// Returns a delegate to convert a value between two types; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide a suitable cast, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this cast.
+ /// </summary>
+ public static Func<TValue, TResult> Convert { get { return convert; } }
+ static Operator()
+ {
+ convert = ExpressionUtil.CreateExpression<TValue, TResult>(body => Expression.Convert(body, typeof(TResult)));
+ add = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Add, true);
+ subtract = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Subtract, true);
+ multiply = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Multiply, true);
+ divide = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Divide, true);
+ }
+
+ private static readonly Func<TResult, TValue, TResult> add, subtract, multiply, divide;
+ /// <summary>
+ /// Returns a delegate to evaluate binary addition (+) for the given types; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<TResult, TValue, TResult> Add { get { return add; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary subtraction (-) for the given types; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<TResult, TValue, TResult> Subtract { get { return subtract; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary multiplication (*) for the given types; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<TResult, TValue, TResult> Multiply { get { return multiply; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary division (/) for the given types; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<TResult, TValue, TResult> Divide { get { return divide; } }
+ }
+
+ /// <summary>
+ /// Provides standard operators (such as addition) over a single type
+ /// </summary>
+ /// <seealso cref="Operator"/>
+ /// <seealso cref="Operator&lt;TValue,TResult&gt;"/>
+ public static class Operator<T>
+ {
+ static readonly INullOp<T> nullOp;
+ internal static INullOp<T> NullOp { get { return nullOp; } }
+
+ static readonly T zero;
+ /// <summary>
+ /// Returns the zero value for value-types (even full Nullable&lt;TInner&gt;) - or null for reference types
+ /// </summary>
+ public static T Zero { get { return zero;} }
+
+ static readonly Func<T, T> negate, not;
+ static readonly Func<T, T, T> or, and, xor;
+ /// <summary>
+ /// Returns a delegate to evaluate unary negation (-) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T> Negate { get { return negate; } }
+ /// <summary>
+ /// Returns a delegate to evaluate bitwise not (~) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T> Not { get { return not; } }
+ /// <summary>
+ /// Returns a delegate to evaluate bitwise or (|) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Or { get { return or; } }
+ /// <summary>
+ /// Returns a delegate to evaluate bitwise and (&amp;) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> And { get { return and; } }
+ /// <summary>
+ /// Returns a delegate to evaluate bitwise xor (^) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Xor { get { return xor; } }
+
+ static readonly Func<T, T, T> add, subtract, multiply, divide;
+ /// <summary>
+ /// Returns a delegate to evaluate binary addition (+) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Add { get { return add; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary subtraction (-) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Subtract { get { return subtract; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary multiplication (*) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Multiply { get { return multiply; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary division (/) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, T> Divide { get { return divide; } }
+
+
+ static readonly Func<T, T, bool> equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual;
+ /// <summary>
+ /// Returns a delegate to evaluate binary equality (==) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> Equal { get { return equal; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary inequality (!=) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> NotEqual { get { return notEqual; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary greater-then (&gt;) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> GreaterThan { get { return greaterThan; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary less-than (&lt;) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> LessThan { get { return lessThan; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary greater-than-or-equal (&gt;=) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> GreaterThanOrEqual { get { return greaterThanOrEqual; } }
+ /// <summary>
+ /// Returns a delegate to evaluate binary less-than-or-equal (&lt;=) for the given type; this delegate will throw
+ /// an InvalidOperationException if the type T does not provide this operator, or for
+ /// Nullable&lt;TInner&gt; if TInner does not provide this operator.
+ /// </summary>
+ public static Func<T, T, bool> LessThanOrEqual { get { return lessThanOrEqual; } }
+
+ static Operator()
+ {
+ add = ExpressionUtil.CreateExpression<T, T, T>(Expression.Add);
+ subtract = ExpressionUtil.CreateExpression<T, T, T>(Expression.Subtract);
+ divide = ExpressionUtil.CreateExpression<T, T, T>(Expression.Divide);
+ multiply = ExpressionUtil.CreateExpression<T, T, T>(Expression.Multiply);
+
+ greaterThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThan);
+ greaterThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThanOrEqual);
+ lessThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThan);
+ lessThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThanOrEqual);
+ equal = ExpressionUtil.CreateExpression<T, T, bool>(Expression.Equal);
+ notEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.NotEqual);
+
+ negate = ExpressionUtil.CreateExpression<T, T>(Expression.Negate);
+ and = ExpressionUtil.CreateExpression<T, T, T>(Expression.And);
+ or = ExpressionUtil.CreateExpression<T, T, T>(Expression.Or);
+ not = ExpressionUtil.CreateExpression<T, T>(Expression.Not);
+ xor = ExpressionUtil.CreateExpression<T, T, T>(Expression.ExclusiveOr);
+
+ Type typeT = typeof(T);
+ if(typeT.IsValueType && typeT.IsGenericType && (typeT.GetGenericTypeDefinition() == typeof(Nullable<>))) {
+ // get the *inner* zero (not a null Nullable<TValue>, but default(TValue))
+ Type nullType = typeT.GetGenericArguments()[0];
+ zero = (T)Activator.CreateInstance(nullType);
+ nullOp = (INullOp<T>)Activator.CreateInstance(
+ typeof(StructNullOp<>).MakeGenericType(nullType));
+ } else {
+ zero = default(T);
+ if (typeT.IsValueType)
+ {
+ nullOp = (INullOp<T>)Activator.CreateInstance(
+ typeof(StructNullOp<>).MakeGenericType(typeT));
+ }
+ else
+ {
+ nullOp = (INullOp<T>)Activator.CreateInstance(
+ typeof(ClassNullOp<>).MakeGenericType(typeT));
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/AnimTest/main.cs b/Samples/AnimTest/main.cs
new file mode 100644
index 00000000..6dd0b525
--- /dev/null
+++ b/Samples/AnimTest/main.cs
@@ -0,0 +1,28 @@
+using System;
+using Crow;
+using Glfw;
+using Samples;
+
+namespace HelloWorld
+{
+ class Program : Interface {
+ Program() : base (800, 600, true) {}
+ static void Main (string[] args) {
+ //Interface.PreferedBackendType = Drawing2D.BackendType.Egl;
+ using (Program app = new Program ()) {
+ //app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Label Text='Hello World' Background='Red' Top='50' Margin='0'/>");
+ //app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Window Caption='hello world'/>");
+ app.Run ();
+ }
+ }
+ protected override void OnInitialized()
+ {
+ Load ("/mnt/devel/crow/Samples/AnimTest/ui/anim.crow");
+ }
+
+ public override void UpdateFrame()
+ {
+ base.UpdateFrame();
+ }
+ }
+}
diff --git a/Samples/AnimTest/ui/anim.crow b/Samples/AnimTest/ui/anim.crow
new file mode 100644
index 00000000..f3fa6c6f
--- /dev/null
+++ b/Samples/AnimTest/ui/anim.crow
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<Container Margin="10" Width="500" Background="/mnt/devel/crow/Samples/AnimTest/ui/background.jpg">
+<!-- <Image Path="/mnt/devel/crow/Samples/AnimTest/ui/background.jpg" SvgSub="True" Height="200"/>-->
+ <HorizontalStack Height="Fit" Width="Fit" Spacing="10" VerticalAlignment="Bottom" >
+ <Label Background="Teal" Width="30%" Margin="10" CornerRadius="10" Font="bold, 14" TextAlignment="Center"/>
+ <Label Background="Teal" Width="30%" Margin="10" CornerRadius="10" Font="bold, 14" TextAlignment="Center"/>
+ <Label Background="Teal" Width="30%" Margin="10" CornerRadius="10" Font="bold, 14" TextAlignment="Center"/>
+ </HorizontalStack>
+</Container>
+
diff --git a/Samples/AnimTest/ui/background.crow b/Samples/AnimTest/ui/background.crow
new file mode 100644
index 00000000..a0881df6
--- /dev/null
+++ b/Samples/AnimTest/ui/background.crow
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<Widget Height="400" Width="260" Background="/mnt/devel/crow/Samples/AnimTest/ui/background.jpg"/>
+<!--<Widget Height="100" Width="100" Background="#Crow.Icons.checkbox.svg"/>-->
+
diff --git a/Samples/AnimTest/ui/background.jpg b/Samples/AnimTest/ui/background.jpg
new file mode 100644
index 00000000..50ebfbf0
--- /dev/null
+++ b/Samples/AnimTest/ui/background.jpg
Binary files differ
diff --git a/Samples/BasicTests/BasicTests.cs b/Samples/BasicTests/BasicTests.cs
index 130171aa..7506d27d 100644
--- a/Samples/BasicTests/BasicTests.cs
+++ b/Samples/BasicTests/BasicTests.cs
@@ -12,19 +12,19 @@ namespace Samples
static void Main ()
{
using (BasicTests app = new BasicTests ()) {
- app.SolidBackground = false;
+ //app.SolidBackground = false;
app.Run ();
}
}
protected override void OnInitialized ()
{
- Commands = new CommandGroup (
+ /*Commands = new CommandGroup (
new Crow.Command("command1", new Action(() => Console.WriteLine ("command1 triggered"))),
new Crow.Command("command2", new Action(() => Console.WriteLine ("command2 triggered"))),
new Crow.Command("command3", new Action(() => Console.WriteLine ("command3 triggered"))),
new Crow.Command("command4", new Action(() => Console.WriteLine ("command4 triggered")))
- );
+ );*/
// += KeyboardKeyDown1;
@@ -55,12 +55,10 @@ namespace Samples
int idx = 0;
string [] testFiles;
-
-
- public override bool OnKeyDown (Key key)
+ public override bool OnKeyDown (KeyEventArgs e)
{
try {
- switch (key) {
+ switch (e.Key) {
case Key.Escape:
Quit ();
break;
@@ -75,7 +73,7 @@ namespace Samples
NotifyValueChanged ("TestList", TestList);
break;
default:
- return base.OnKeyDown (key);
+ return base.OnKeyDown (e);
}
ClearInterface ();
diff --git a/Samples/HelloWorld/main.cs b/Samples/HelloWorld/main.cs
index fd70a2b9..fdf75a8d 100644
--- a/Samples/HelloWorld/main.cs
+++ b/Samples/HelloWorld/main.cs
@@ -8,6 +8,7 @@ namespace HelloWorld
class Program : Interface {
Program() : base (800, 600, true) {}
static void Main (string[] args) {
+ //Interface.PreferedBackendType = Drawing2D.BackendType.Egl;
using (Program app = new Program ()) {
//app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Label Text='Hello World' Background='Red' Top='50' Margin='0'/>");
//app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Window Caption='hello world'/>");
diff --git a/Samples/HelloWorld/ui/helloworld.crow b/Samples/HelloWorld/ui/helloworld.crow
index d1c30b0f..874667c2 100644
--- a/Samples/HelloWorld/ui/helloworld.crow
+++ b/Samples/HelloWorld/ui/helloworld.crow
@@ -1,2 +1,9 @@
<?xml version="1.0"?>
-<Label Text="Hello World"/>
+
+ <!--<Widget Background="hgradient|0:Black|0.5:Blue|1:Red" Margin="100" />-->
+ <VerticalStack>
+ <Image Path="#Crow.Icons.checkbox.svg" SvgSub="True" Height="200"/>
+ <CheckBox/>
+
+ </VerticalStack>
+ <!--<ColorPicker/>-->
diff --git a/Samples/ShowCase/ShowCase.cs b/Samples/ShowCase/ShowCase.cs
index 958a6b13..92a71e9f 100644
--- a/Samples/ShowCase/ShowCase.cs
+++ b/Samples/ShowCase/ShowCase.cs
@@ -14,6 +14,7 @@ using Crow.Text;
using System.Collections.Generic;
using Encoding = System.Text.Encoding;
using Samples;
+using System.Threading;
namespace ShowCase
{
@@ -30,6 +31,8 @@ namespace ShowCase
};
static void Main ()
{
+ //Interface.PreferedBackendType = Drawing2D.BackendType.Egl;
+
initDebugLog ();
Environment.SetEnvironmentVariable ("FONTCONFIG_PATH", @"C:\Users\Jean-Philippe\source\vcpkg\installed\x64-windows\tools\fontconfig\fonts");
@@ -44,6 +47,40 @@ namespace ShowCase
app.Run ();
}
}
+ public override void Run () {
+ initBackend ();
+
+ if (!SingleThreaded) {
+ Thread t = new Thread (InterfaceThread) {
+ IsBackground = true
+ };
+ t.Start ();
+ }
+
+ Init ();
+
+ if (SingleThreaded) {
+ while (!Glfw3.WindowShouldClose (WindowHandle)) {
+ Glfw3.PollEvents ();
+ try {
+ Update();
+ UpdateFrame ();
+ } catch (Exception ex) {
+ showError (ex);
+ crowContainer.SetChild (null);
+ }
+ Thread.Sleep (UPDATE_INTERVAL);
+ }
+ } else {
+ while (!Glfw3.WindowShouldClose (hWin)) {
+ Glfw3.PollEvents ();
+ UpdateFrame ();
+ Thread.Sleep (POLLING_INTERVAL);
+ }
+ }
+
+ Terminate ();
+ }
public Container crowContainer;
Stopwatch reloadChrono = new Stopwatch ();
diff --git a/Samples/ShowCase/ui/showcase.crow b/Samples/ShowCase/ui/showcase.crow
index 298c8797..b1d6fb88 100644
--- a/Samples/ShowCase/ui/showcase.crow
+++ b/Samples/ShowCase/ui/showcase.crow
@@ -77,7 +77,7 @@
<Container Name="CrowContainer" Height="60%" Background="Black"/>
<Splitter/>
<VerticalStack CacheEnabled="true">
- <Menu Data="{EditorAllCommands}" Height="Fit" Width="Stretched">
+ <!--<Menu Data="{EditorAllCommands}" Height="Fit" Width="Stretched">
<ItemTemplate DataType="Crow.Command" Path="Interfaces/menuCommand.itmp"/>
<ItemTemplate DataType="Crow.CommandGroup" >
<MenuItem Data="{Commands}" Width="Fit" IsEnabled="{CanExecute}"
@@ -85,8 +85,8 @@
ItemTemplate="Interfaces/menuItem.itmp">
</MenuItem>
</ItemTemplate>
- </Menu>
- <!-- <Wrapper Orientation="Vertical" Height="Fit">
+ </Menu>-->
+ <Wrapper Orientation="Vertical" Height="Fit">
<Button Style="IcoButton" Command="{CMDNew}" />
<Button Style="IcoButton" Command="{CMDSave}" />
<Button Style="IcoButton" Command="{CMDSaveAs}" />
@@ -160,11 +160,11 @@
Tooltip="Add '*source* where you want to load the source in the editor."/>
</VerticalStack>
</Popper>
- </Wrapper>-->
+ </Wrapper>
<HorizontalStack>
<Editor Name="tb" Text="{Source}" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"
TextChanged="onTextChanged" KeyDown="textView_KeyDown" ContextCommands="{EditorEditCommands}"
- SelectionChanged="onEditorSelectionChanged"
+ SelectionChanged="onEditorSelectionChanged" ClipToClientRect="true"
Foreground="DarkGrey" Background="White" MouseWheelSpeed="20"/>
<ScrollBar Value="{²../tb.ScrollY}"
LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
diff --git a/Samples/common/ui/Interfaces/Experimental/svg.crow b/Samples/common/ui/Interfaces/Experimental/svg.crow
new file mode 100644
index 00000000..7a935032
--- /dev/null
+++ b/Samples/common/ui/Interfaces/Experimental/svg.crow
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<Image Path="/usr/share/icons/breeze/categories/32/applications-education.svg"/> \ No newline at end of file
diff --git a/Samples/common/ui/Interfaces/TemplatedContainer/buttons.crow b/Samples/common/ui/Interfaces/TemplatedContainer/buttons.crow
new file mode 100644
index 00000000..32a5b83f
--- /dev/null
+++ b/Samples/common/ui/Interfaces/TemplatedContainer/buttons.crow
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VerticalStack Margin="10" Background="Grey">
+ <Button
+ Foreground="LightGrey"
+ MouseEnter="{Foreground=White}"
+ MouseLeave="{Foreground=LightGrey}"
+ Background="vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet"
+ MouseUp="{Background=vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet}"
+ MouseDown="{Background=vgradient|0:Jet|0.1:Grey|0.9:Grey|1:LightGrey}">
+ <Template>
+ <Border Foreground="Black" CornerRadius="10" Background="{./Background}" Margin="7">
+ <Label Foreground="{./Foreground}" Text="{./Caption}"/>
+ </Border>
+ </Template>
+ </Button >
+ <CheckBox Width="200"
+ Foreground="Black"
+ Background="vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet"
+ Unchecked="{Background=vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet};{Foreground=Black}"
+ Checked="{Background=vgradient|0:Jet|0.1:Grey|0.9:Grey|1:LightGrey};{Foreground=DodgerBlue}">
+ <Template>
+ <Border Foreground="{./Foreground}" CornerRadius="10" Background="{./Background}" Margin="7">
+ <Label Text="{./Caption}"/>
+ </Border>
+ </Template>
+ </CheckBox >
+ <HorizontalStack Height="Fit" Width="Fit">
+ <RadioButton Width="200"
+ Foreground="Black"
+ Background="vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet"
+ Unchecked="{Background=vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet};{Foreground=Black}"
+ Checked="{Background=vgradient|0:Jet|0.1:Grey|0.9:Grey|1:LightGrey};{Foreground=DodgerBlue}">
+ <Template>
+ <Border Foreground="{./Foreground}" CornerRadius="10" Background="{./Background}" Margin="7">
+ <Label Text="{./Caption}"/>
+ </Border>
+ </Template>
+ </RadioButton >
+ <RadioButton Width="200"
+ Foreground="Black"
+ Background="vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet"
+ Unchecked="{Background=vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet};{Foreground=Black}"
+ Checked="{Background=vgradient|0:Jet|0.1:Grey|0.9:Grey|1:LightGrey};{Foreground=DodgerBlue}">
+ <Template>
+ <Border Foreground="{./Foreground}" CornerRadius="10" Background="{./Background}" Margin="7">
+ <Label Text="{./Caption}"/>
+ </Border>
+ </Template>
+ </RadioButton >
+ <RadioButton Width="200"
+ Foreground="Black"
+ Background="vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet"
+ Unchecked="{Background=vgradient|0:LightGrey|0.1:Grey|0.9:Grey|1:Jet};{Foreground=Black}"
+ Checked="{Background=vgradient|0:Jet|0.1:Grey|0.9:Grey|1:LightGrey};{Foreground=DodgerBlue}">
+ <Template>
+ <Border Foreground="{./Foreground}" CornerRadius="10" Background="{./Background}" Margin="7">
+ <Label Text="{./Caption}"/>
+ </Border>
+ </Template>
+ </RadioButton >
+ </HorizontalStack>
+</VerticalStack> \ No newline at end of file