<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
- <ReleaseVersion>$(CrowVersion)</ReleaseVersion>
+ <ReleaseVersion>0.8.0</ReleaseVersion>
<AssemblyVersion>$(CrowVersion)</AssemblyVersion>
<Title>C# Rapid Open Widget Toolkit</Title>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
- <DefineConstants>DEBUG;TRACE;MEASURE_TIME;_DEBUG_DISPOSE;_DEBUG_BINDING;DESIGN_MODE;_DEBUG_CLIP_RECTANGLE;_DEBUG_FOCUS;_DEBUG_DRAGNDROP;_DEBUG_LOG</DefineConstants>
+ <DefineConstants>DEBUG;TRACE;MEASURE_TIME;_DEBUG_DISPOSE;_DEBUG_BINDING;DESIGN_MODE;_DEBUG_CLIP_RECTANGLE;_DEBUG_FOCUS;DEBUG_DRAGNDROP;_DEBUG_LOG</DefineConstants>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
+++ /dev/null
-//
-// BmpPicture.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using Crow.Cairo;
-
-namespace Crow
-{
-
- /// <summary>
- /// Derived from FILL for loading and drawing bitmaps in the interface
- /// </summary>
- public class BmpPicture : Picture
- {
- byte[] image = null;
-
- #region CTOR
- /// <summary>
- /// Initializes a new instance of BmpPicture.
- /// </summary>
- public BmpPicture ()
- {}
- /// <summary>
- /// Initializes a new instance of BmpPicture by loading the image pointed by the path argument
- /// </summary>
- /// <param name="path">image path, may be embedded</param>
- public BmpPicture (string path) : base(path)
- {
- Load ();
- }
- #endregion
- /// <summary>
- /// load the image for rendering from the path given as argument
- /// </summary>
- /// <param name="path">image path, may be embedded</param>
- void Load ()
- {
- if (sharedResources.ContainsKey (Path)) {
- sharedPicture sp = sharedResources [Path];
- image = (byte[])sp.Data;
- Dimensions = sp.Dims;
- return;
- }
- using (Stream stream = Interface.StaticGetStreamFromPath (Path)) {
- using (StbImage stbi = new StbImage (stream)) {
- image = new byte [stbi.Size];
- //rgba to argb for cairo.
- for (int i = 0; i < stbi.Size; i+=4) {
- image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
- image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
- image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
- image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
- }
- Dimensions = new Size (stbi.Width, stbi.Height);
- }
-
- //loadBitmap (new System.Drawing.Bitmap (stream));
- }
- sharedResources [Path] = new sharedPicture (image, Dimensions);
- }
-
-
-
- //load image via System.Drawing.Bitmap, cairo load png only
- /*void loadBitmap (System.Drawing.Bitmap bitmap)
- {
- if (bitmap == null)
- return;
-
- System.Drawing.Imaging.BitmapData data = bitmap.LockBits
- (new System.Drawing.Rectangle (0, 0, bitmap.Width, bitmap.Height),
- System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
-
- Dimensions = new Size (bitmap.Width, bitmap.Height);
-
- int stride = data.Stride;
- int bitmapSize = Math.Abs (data.Stride) * bitmap.Height;
-
- image = new byte[bitmapSize];
- System.Runtime.InteropServices.Marshal.Copy (data.Scan0, image, 0, bitmapSize);
-
- bitmap.UnlockBits (data);
- }*/
-
- #region implemented abstract members of Fill
-
- public override void SetAsSource (Context ctx, Rectangle bounds = default(Rectangle))
- {
- float widthRatio = 1f;
- float heightRatio = 1f;
-
- if (Scaled){
- widthRatio = (float)bounds.Width / Dimensions.Width;
- heightRatio = (float)bounds.Height / Dimensions.Height;
- }
-
- if (KeepProportions) {
- if (widthRatio < heightRatio)
- heightRatio = widthRatio;
- else
- widthRatio = heightRatio;
- }
-
- using (ImageSurface tmp = new ImageSurface (Format.Argb32, bounds.Width, bounds.Height)) {
- using (Context gr = new Context (tmp)) {
- gr.Translate (bounds.Left, bounds.Top);
- gr.Scale (widthRatio, heightRatio);
- gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
-
- using (ImageSurface imgSurf = new ImageSurface (image, Format.Argb32,
- Dimensions.Width, Dimensions.Height, 4 * Dimensions.Width)) {
- gr.SetSourceSurface (imgSurf, 0,0);
- gr.Paint ();
- }
- }
- ctx.SetSource (tmp);
- }
- }
- #endregion
-
- /// <summary>
- /// paint the image in the rectangle given in arguments according
- /// to the Scale and keepProportion parameters.
- /// </summary>
- /// <param name="gr">drawing Backend context</param>
- /// <param name="rect">bounds of the target surface to paint</param>
- /// <param name="subPart">used for svg only</param>
- public override void Paint (Context gr, Rectangle rect, string subPart = "")
- {
- float widthRatio = 1f;
- float heightRatio = 1f;
-
- if (Scaled){
- widthRatio = (float)rect.Width / Dimensions.Width;
- heightRatio = (float)rect.Height / Dimensions.Height;
- }
-
- if (KeepProportions) {
- if (widthRatio < heightRatio)
- heightRatio = widthRatio;
- else
- widthRatio = heightRatio;
- }
-
- gr.Save ();
-
- gr.Translate (rect.Left,rect.Top);
- gr.Scale (widthRatio, heightRatio);
- gr.Translate ((rect.Width/widthRatio - Dimensions.Width)/2, (rect.Height/heightRatio - Dimensions.Height)/2);
-
- using (ImageSurface imgSurf = new ImageSurface (image, Format.Argb32,
- Dimensions.Width, Dimensions.Height, 4 * Dimensions.Width)) {
- gr.SetSourceSurface (imgSurf, 0,0);
- gr.Paint ();
- }
- gr.Restore ();
- }
- }
-}
-
-//
-// Colors.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Xml.Serialization;
-using System.Reflection;
-using System.Diagnostics;
-
-
namespace Crow
{
+++ /dev/null
-// Copyright (c) 2013-2020 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.Reflection.Emit;
-using System.Reflection;
-using System.Diagnostics;
-using System.Linq;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using System.Xml;
-using Crow.IML;
-using System.Text;
-
-namespace Crow.IML
-{
- public static class CompilerServices
- {
- /// <summary>
- /// known types cache, prevent rewalking all the assemblies of the domain
- /// the key is the type simple name
- /// </summary>
- internal static Dictionary<string, Type> knownTypes = new Dictionary<string, Type> ();
- /// <summary>
- /// known extension methods.
- /// key is type dot memberName.
- /// </summary>
- internal static Dictionary<string, MethodInfo> knownExtMethods = new Dictionary<string, MethodInfo> ();
-
- internal static MethodInfo stringEquals = typeof (string).GetMethod("Equals", new Type [3] { typeof (string), typeof (string), typeof (StringComparison) });
- internal static MethodInfo miObjToString = typeof(object).GetMethod("ToString");
- internal static MethodInfo miGetType = typeof(object).GetMethod("GetType");
- internal static MethodInfo miParseEnum = typeof(Enum).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
- Type.DefaultBinder, new Type [] {typeof (Type), typeof (string), typeof (bool)}, null);
-
- internal static MethodInfo miGetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
- internal static MethodInfo miGetEvent = typeof(Type).GetMethod("GetEvent", new Type[] {typeof(string)});
-
- internal static MethodInfo miMIInvoke = typeof(MethodInfo).GetMethod ("Invoke", new Type[] {
- typeof(object),
- typeof(object[])
- });
-
- internal static MethodInfo miCreateBoundDel = typeof(Delegate).GetMethod ("CreateDelegate", new Type[] { typeof(Type), typeof(object), typeof(MethodInfo) });//create bound delegate
- internal static MethodInfo miGetColCount = typeof(System.Collections.ICollection).GetProperty("Count").GetGetMethod();
- internal static MethodInfo miGetDelegateListItem = typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) });
-
- internal static MethodInfo miCompileDynEventHandler = typeof(CompilerServices).GetMethod ("compileDynEventHandler", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miRemEvtHdlByName = typeof(CompilerServices).GetMethod("removeEventHandlerByName", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miRemEvtHdlByTarget = typeof(CompilerServices).GetMethod("removeEventHandlerByTarget", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miGetMethInfoWithRefx = typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miGetMembIinfoWithRefx = typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miSetValWithRefx = typeof(CompilerServices).GetMethod("setValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miGetValWithRefx = typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miCreateDel = typeof(CompilerServices).GetMethod ("createDel", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.NonPublic);
- internal static MethodInfo miGetDataTypeAndFetch = typeof(CompilerServices).GetMethod("getDataTypeAndFetch", BindingFlags.Static | BindingFlags.NonPublic);
-
-
- internal static MethodInfo miGoUpLevels = typeof(CompilerServices).GetMethod("goUpNbLevels", BindingFlags.Static | BindingFlags.NonPublic);
-
- internal static FieldInfo fiCachedDel = typeof(Instantiator).GetField("cachedDelegates", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static FieldInfo fiTemplateBinding = typeof(Instantiator).GetField("templateBinding", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static MethodInfo miDSChangeEmitHelper = typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static MethodInfo miDSReverseBinding = typeof(Instantiator).GetMethod("dataSourceReverseBinding", BindingFlags.Static | BindingFlags.NonPublic);
-
- internal static FieldInfo miSetCurIface = typeof(Widget).GetField ("IFace", BindingFlags.Public | BindingFlags.Instance);
- internal static MethodInfo miFindByName = typeof (Widget).GetMethod ("FindByName");
- internal static MethodInfo miGetGObjItem = typeof(List<Widget>).GetMethod("get_Item", new Type[] { typeof(Int32) });
- internal static MethodInfo miLoadDefaultVals = typeof (Widget).GetMethod ("loadDefaultValues");
- internal static PropertyInfo piStyle = typeof (Widget).GetProperty ("Style");
- internal static MethodInfo miGetLogicalParent = typeof(Widget).GetProperty("LogicalParent").GetGetMethod();
- internal static MethodInfo miGetDataSource = typeof(Widget).GetProperty("DataSource").GetGetMethod ();
- internal static EventInfo eiLogicalParentChanged = typeof(Widget).GetEvent("LogicalParentChanged");
-
- internal static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("CreateInstance", BindingFlags.Instance | BindingFlags.Public);
- internal static MethodInfo miIFaceCreateTemplateInst = typeof (Interface).GetMethod ("CreateTemplateInstance", BindingFlags.Instance | BindingFlags.Public);
- internal static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate", BindingFlags.Instance | BindingFlags.Public);
-
- internal static MethodInfo miAddITemp = typeof(Dictionary<string, ItemTemplate>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) });
- internal static MethodInfo miGetITempFromDic = typeof(Dictionary<string, ItemTemplate>).GetMethod ("get_Item", new Type[] { typeof(string) });
- internal static FieldInfo fldItemTemplates = typeof(TemplatedGroup).GetField("ItemTemplates");
- internal static MethodInfo miLoadPage = typeof(TemplatedGroup).GetMethod ("loadPage", BindingFlags.Instance | BindingFlags.NonPublic| BindingFlags.Public);
- internal static MethodInfo miIsAlreadyExpanded = typeof(TemplatedGroup).GetMethod("emitHelperIsAlreadyExpanded", BindingFlags.Instance | BindingFlags.NonPublic);
-
- internal static MethodInfo miCreateExpDel = typeof(ItemTemplate).GetMethod ("CreateExpandDelegate");
- internal static FieldInfo fiFetchMethodName = typeof(ItemTemplate).GetField("fetchMethodName", BindingFlags.Instance | BindingFlags.NonPublic);
-
- #if DESIGN_MODE
- internal static MethodInfo miDicStrStrAdd = typeof(Dictionary<string, string>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(string) });
- #endif
-
- #region tree handling methods
- internal static FieldInfo fiChild = typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static MethodInfo miSetChild = typeof (Container).GetMethod ("SetChild");
- internal static MethodInfo miAddChild = typeof (Group).GetMethod ("AddChild");
- internal static FieldInfo fiChildren = typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static MethodInfo miLoadTmp = typeof (TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic);
- internal static PropertyInfo piContent = typeof(TemplatedContainer).GetProperty ("Content");
- internal static MethodInfo miAddItem = typeof (TemplatedGroup).GetMethod ("AddItem", BindingFlags.Instance | BindingFlags.Public);
- internal static MethodInfo miGetItems = typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ();
- #endregion
-
- #region ValueChange & DSChange Reflexion member info
- internal static EventInfo eiValueChange = typeof (IValueChange).GetEvent ("ValueChanged");
- internal static MethodInfo miInvokeValueChange = eiValueChange.EventHandlerType.GetMethod ("Invoke");
- internal static Type [] argsBoundValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
- internal static Type [] argsValueChange = { typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
- internal static FieldInfo fiVCNewValue = typeof (ValueChangeEventArgs).GetField ("NewValue");
- internal static FieldInfo fiVCMbName = typeof (ValueChangeEventArgs).GetField ("MemberName");
-
- internal static EventInfo eiDSChange = typeof (Widget).GetEvent ("DataSourceChanged");
- internal static MethodInfo miInvokeDSChange = eiDSChange.EventHandlerType.GetMethod ("Invoke");
- internal static Type [] argsBoundDSChange = {typeof (object), typeof (object), miInvokeDSChange.GetParameters () [1].ParameterType };
- internal static FieldInfo fiDSCNewDS = typeof (DataSourceChangeEventArgs).GetField ("NewDataSource");
- internal static FieldInfo fiDSCOldDS = typeof (DataSourceChangeEventArgs).GetField ("OldDataSource");
- internal static Type ehTypeDSChange = eiDSChange.EventHandlerType;
- #endregion
-
- /// <summary>
- /// Loc0 is the current graphic object and arg2 of loader is the current interface
- /// </summary>
- /// <param name="il">Il.</param>
- public static void emitSetCurInterface(ILGenerator il){
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldarg_1);
- il.Emit (OpCodes.Stfld, miSetCurIface);
- }
-
- public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){
- il.Emit (OpCodes.Ldloc_0);
-
- if (val == null) {
- il.Emit (OpCodes.Ldnull);
- il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
- return;
- }
- Type dvType = val.GetType ();
-
- if (dvType.IsValueType) {
- if (pi.PropertyType.IsValueType) {
- if (pi.PropertyType.IsEnum) {
- if (pi.PropertyType != dvType)
- throw new Exception ("Enum mismatch in default values: " + pi.PropertyType.FullName);
- il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val));
- } else {
- switch (Type.GetTypeCode (dvType)) {
- case TypeCode.Boolean:
- if ((bool)val == true)
- il.Emit (OpCodes.Ldc_I4_1);
- else
- il.Emit (OpCodes.Ldc_I4_0);
- break;
-// case TypeCode.Empty:
-// break;
-// case TypeCode.Object:
-// break;
-// case TypeCode.DBNull:
-// break;
-// case TypeCode.SByte:
-// break;
-// case TypeCode.Decimal:
-// break;
-// case TypeCode.DateTime:
-// break;
- case TypeCode.Char:
- il.Emit (OpCodes.Ldc_I4, Convert.ToChar (val));
- break;
- case TypeCode.Byte:
- case TypeCode.Int16:
- case TypeCode.Int32:
- il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val));
- break;
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- il.Emit (OpCodes.Ldc_I4, Convert.ToUInt32 (val));
- break;
- case TypeCode.Int64:
- il.Emit (OpCodes.Ldc_I8, Convert.ToInt64 (val));
- break;
- case TypeCode.UInt64:
- il.Emit (OpCodes.Ldc_I8, Convert.ToUInt64 (val));
- break;
- case TypeCode.Single:
- il.Emit (OpCodes.Ldc_R4, Convert.ToSingle (val));
- break;
- case TypeCode.Double:
- il.Emit (OpCodes.Ldc_R8, Convert.ToDouble (val));
- break;
- case TypeCode.String:
- il.Emit (OpCodes.Ldstr, Convert.ToString (val));
- break;
- default:
- il.Emit (OpCodes.Pop);
- return;
- }
- }
- } else
- throw new Exception ("Expecting valuetype in default values for: " + pi.Name);
- }else{
- //surely a class or struct
- if (dvType != typeof(string))
- throw new Exception ("Expecting String in default values for: " + pi.Name);
- if (pi.PropertyType == typeof(string))
- il.Emit (OpCodes.Ldstr, Convert.ToString (val));
- else if (pi.PropertyType.IsEnum) {
- //load type of enum
- il.Emit(OpCodes.Ldtoken, pi.PropertyType);
- il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
- //load enum value name
- il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:implement here string format?
- //load false
- il.Emit (OpCodes.Ldc_I4_0);
- il.Emit (OpCodes.Call, CompilerServices.miParseEnum);
-
- if (CompilerServices.miParseEnum.ReturnType != pi.PropertyType)
- il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
- } else {
- MethodInfo miParse = pi.PropertyType.GetMethod
- ("Parse", BindingFlags.Static | BindingFlags.Public,
- Type.DefaultBinder, new Type [] {typeof (string)},null);
- if (miParse == null)
- throw new Exception ("no Parse method found for: " + pi.PropertyType.FullName);
-
- il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:is this convert required?
- il.Emit (OpCodes.Call, miParse);
-
- if (miParse.ReturnType != pi.PropertyType)
- il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
- }
- }
- il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
- }
-
- #region conversions
-
- internal static MethodInfo GetConvertMethod (Type targetType)
- {
- string name;
-
- if (targetType == typeof (bool))
- name = "ToBoolean";
- else if (targetType == typeof (byte))
- name = "ToByte";
- else if (targetType == typeof (short))
- name = "ToInt16";
- else if (targetType == typeof (int))
- name = "ToInt32";
- else if (targetType == typeof (uint))
- name = "ToUInt32";
- else if (targetType == typeof (long))
- name = "ToInt64";
- else if (targetType == typeof (double))
- name = "ToDouble";
- else if (targetType == typeof (float))
- name = "ToSingle";
- else if (targetType == typeof (string))
- return typeof (object).GetMethod ("ToString", Type.EmptyTypes);
- else //try to find implicit convertion
- throw new NotImplementedException (string.Format ("Conversion to {0} is not implemented.", targetType.Name));
-
- return typeof (Convert).GetMethod (name, BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (object) }, null);
- }
- #endregion
-
- #region Reflexion helpers
- static MemberInfo getMemberInfoWithReflexion(object instance, string member){
- Type t = instance.GetType();
-#if DEBUG_BINDING_FUNC_CALLS
- Console.WriteLine ($"getMemberInfoWithReflexion ({instance},{member}); type:{t}");
-#endif
- MemberInfo mi = t.GetMember (member)?.FirstOrDefault();
- if (mi == null)
- mi = CompilerServices.SearchExtMethod (t, member);
- return mi;
- }
- static MethodInfo getMethodInfoWithReflexion(object instance, string method){
-#if DEBUG_BINDING_FUNC_CALLS
- Console.WriteLine ($"getMethodInfoWithReflexion ({instance},{method}); type:{instance.GetType ()}");
-#endif
- return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
- }
- /// <summary>
- /// set value, convert if required
- /// </summary>
- /// <param name="dest">Destination instance</param>
- /// <param name="value">Value</param>
- /// <param name="destMember">Destination member</param>
- static void setValueWithReflexion(object dest, object value, string destMember){
-#if DEBUG_BINDING_FUNC_CALLS
- Console.WriteLine ($"setValueWithReflexion (dest:{dest},value:{value},member:{destMember});");
-#endif
- Type destType = null;
- Type origType = null;
- object convertedVal = null;
-
- MemberInfo miDest = getMemberInfoWithReflexion (dest, destMember);
-
- if (miDest == null) {
- Debug.WriteLine ("Reverse template binding error: " + destMember + " not found in " + dest);
- return;
- }
-
- destType = CompilerServices.GetMemberInfoType (miDest);
-
- try {
- if (value != null) {
- if (destType == typeof (object))//TODO: check that test of destType is not causing problems
- convertedVal = value;
- else {
- origType = value.GetType ();
- if (destType.IsAssignableFrom (origType))
- convertedVal = Convert.ChangeType (value, destType);
- else if (origType == typeof(string) & destType.IsPrimitive)
- convertedVal = Convert.ChangeType(value, destType);
- else if (origType.IsPrimitive & destType.IsPrimitive)
- convertedVal = GetConvertMethod (destType).Invoke (null, new Object[] { value });
- else
- convertedVal = getImplicitOp (origType, destType).Invoke (value, null);
- }
- }
- } catch (Exception ex) {
- Debug.WriteLine (ex.ToString ());
- return;
- }
-
- if (miDest.MemberType == MemberTypes.Property)
- (miDest as PropertyInfo).SetValue (dest, convertedVal);
- else if (miDest.MemberType == MemberTypes.Field)
- (miDest as FieldInfo).SetValue (dest, convertedVal);
- }
- /// <summary>
- /// Gets value with reflexion, return empty string ("") for string and object and return
- /// default value for valueType data.
- /// </summary>
- static object getValueWithReflexion(object instance, MemberInfo mi){
-#if DEBUG_BINDING_FUNC_CALLS
- Console.WriteLine ($"getValueWithReflexion ({instance},{mi});");
-#endif
- object tmp = null;
- Type dstType = null;
- if (mi == null)
- return null;
- try {
- if (mi.MemberType == MemberTypes.Property) {
- PropertyInfo pi = mi as PropertyInfo;
- tmp = pi.GetValue (instance);
- dstType = pi.PropertyType;
- }else if (mi.MemberType == MemberTypes.Field) {
- FieldInfo fi = mi as FieldInfo;
- tmp = fi.GetValue (instance);
- dstType = fi.FieldType;
- }else if (mi.MemberType == MemberTypes.Method) {
- MethodInfo gi = mi as MethodInfo;
- if (gi.IsStatic)
- tmp = gi.Invoke(null, new object[] {instance});
- else
- tmp = gi.Invoke(instance, null);
- dstType = gi.ReturnType;
- }
- if (tmp != null)
- return tmp;
- if (dstType == typeof(string) || dstType == typeof (object))//TODO:object should be allowed to return null and not ""
- return "";
- if (dstType.IsValueType)
- return Activator.CreateInstance (dstType);
- } catch (Exception ex) {
- Debug.WriteLine (ex.ToString ());
- return "";
- }
-
- return null;
- }
- internal static MethodInfo SearchExtMethod (Type t, string methodName)
- {
- string key = t.Name + "." + methodName;
- if (knownExtMethods.ContainsKey (key))
- return knownExtMethods [key];
-
- //Console.WriteLine ($"*** search extension method: {t};{methodName} => key={key}");
-
- MethodInfo mi = null;
- mi = GetExtensionMethods (Assembly.GetEntryAssembly (), t, methodName);
- if (mi == null)
- mi = GetExtensionMethods (t.Module.Assembly, t, methodName);
-
- //add key even if mi is null to prevent searching again and again for propertyless bindings
- knownExtMethods.Add (key, mi);
- return mi;
- }
-
- public static MethodInfo GetExtensionMethods (Assembly assembly, Type extendedType, string methodName)
- {
- foreach (Type t in assembly.GetTypes ().Where
- (ty => ty.IsDefined (typeof (ExtensionAttribute), false))) {
- foreach (MethodInfo mi in t.GetMethods
- (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Where
- (m=> m.Name == methodName && m.IsDefined (typeof (ExtensionAttribute), false) &&
- m.GetParameters ().Length == 1)) {
- Type curType = extendedType;
- while (curType != null) {
- if (mi.GetParameters () [0].ParameterType == curType)
- return mi;
- curType = curType.BaseType;
- }
- }
-
- }
- return null;
- }
- /// <summary>
- /// retrieve event handler in class or ancestors
- /// </summary>
- static FieldInfo getEventHandlerField (Type type, string eventName)
- {
- FieldInfo fi;
- Type ty = type;
- do {
- fi = ty.GetField (eventName,
- BindingFlags.NonPublic |
- BindingFlags.Instance |
- BindingFlags.GetField);
- ty = ty.BaseType;
- if (ty == null)
- break;
- } while (fi == null);
- return fi;
- }
- /// <summary>
- /// search for an implicit conversion method in origine or destination classes
- /// </summary>
- static MethodInfo getImplicitOp(Type origType, Type dstType){
- foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
- if (mi.Name == "op_Implicit") {
- if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
- return mi;
- }
- }
- foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
- if (mi.Name == "op_Implicit") {
- if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
- return mi;
- }
- }
- return null;
- }
-#endregion
-
- /// <summary>
- /// Emits tree parsing command to fetch dest instance starting from orig node
- /// </summary>
- internal static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){
- int ptr = 0;
- while (orig [ptr] == dest [ptr]) {
- ptr++;
- if (ptr == orig.Count || ptr == dest.Count)
- break;
- }
- for (int i = 0; i < orig.Count - ptr; i++)
- il.Emit (OpCodes.Callvirt, CompilerServices.miGetLogicalParent);
- while (ptr < dest.Count) {
- emitGetChild (il, dest [ptr-1].CrowType, dest [ptr].Index);
- ptr++;
- }
- }
- /// <summary>
- /// Emits tree parsing commands to get child starting at root node
- /// </summary>
- /// <param name="il">MSIL generator</param>
- /// <param name="dest">Absolute Node Address of the instance to get</param>
- internal static void emitGetInstance (ILGenerator il, NodeAddress dest){
- if (dest == null)
- return;
- for (int i = 0; i < dest.Count - 1; i++)
- emitGetChild (il, dest [i].CrowType, dest [i + 1].Index);
- }
- /// <summary>
- /// Emits msil to fetch chil instance of current GraphicObject on the stack
- /// </summary>
- /// <param name="il">Il generator</param>
- /// <param name="parentType">Parent type</param>
- /// <param name="index">Index of child, -1 for template root</param>
- internal static void emitGetChild(ILGenerator il, Type parentType, int index){
- if (typeof (Group).IsAssignableFrom (parentType)) {
- il.Emit (OpCodes.Ldfld, fiChildren);
- il.Emit(OpCodes.Ldc_I4, index);
- il.Emit (OpCodes.Callvirt, miGetGObjItem);
- return;
- }
- if (typeof(Container).IsAssignableFrom (parentType) || index < 0) {
- il.Emit (OpCodes.Ldfld, fiChild);
- return;
- }
- if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) {
- il.Emit (OpCodes.Callvirt, piContent.GetGetMethod());
- return;
- }
- if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) {
- il.Emit (OpCodes.Callvirt, miGetItems);
- il.Emit(OpCodes.Ldc_I4, index);
- il.Emit (OpCodes.Callvirt, miGetGObjItem);
- return;
- }
- }
-
- /// <summary>
- /// Emit MSIL for conversion from orig type to dest type
- /// </summary>
- internal static void emitConvert(ILGenerator il, Type origType, Type destType){
- if (destType == typeof(object))
- return;
- if (destType == typeof (string)) {
- System.Reflection.Emit.Label emitNullStr = il.DefineLabel ();
- System.Reflection.Emit.Label endConvert = il.DefineLabel ();
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Brfalse, emitNullStr);
- il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
- il.Emit (OpCodes.Br, endConvert);
- il.MarkLabel (emitNullStr);
- il.Emit (OpCodes.Pop);//remove null string from stack
- il.Emit (OpCodes.Ldstr, "");//replace with empty string
- il.MarkLabel (endConvert);
- } else if ((origType.IsEnum || origType == typeof (Enum)) && destType.IsEnum) {
- il.Emit (OpCodes.Unbox_Any, destType);
- return;
- } else if (origType.IsValueType) {
- if (destType != origType) {
- MethodInfo miIO = getImplicitOp (origType, destType);
- if (miIO != null) {
- System.Reflection.Emit.Label emitCreateDefault = il.DefineLabel ();
- System.Reflection.Emit.Label emitContinue = il.DefineLabel ();
- LocalBuilder lbStruct = il.DeclareLocal (origType);
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Brfalse, emitCreateDefault);
- il.Emit (OpCodes.Unbox_Any, origType);
- il.Emit (OpCodes.Br, emitContinue);
- il.MarkLabel (emitCreateDefault);
- il.Emit (OpCodes.Pop);//pop null value
- il.Emit (OpCodes.Ldloca, lbStruct);
- il.Emit (OpCodes.Initobj, origType);
- il.Emit (OpCodes.Ldloc, lbStruct);
- il.MarkLabel (emitContinue);
- il.Emit (OpCodes.Call, miIO);
- } else {
- MethodInfo miconv = CompilerServices.GetConvertMethod (destType);
- if (miconv.IsStatic)
- il.Emit (OpCodes.Call, miconv);
- else
- il.Emit (OpCodes.Callvirt, miconv);
- }
- } else
- il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this
- } else {
- if (destType.IsAssignableFrom (origType))
- il.Emit (OpCodes.Castclass, destType);
- else {
- if (origType == typeof (string)) {
- //search dest type for parse method
- MethodInfo miParse = destType.GetMethod
- ("Parse", BindingFlags.Static | BindingFlags.Public,
- Type.DefaultBinder, new Type [] { typeof (string) }, null);
- if (miParse == null)
- throw new Exception ("no Parse method found for: " + destType.FullName);
- il.Emit (OpCodes.Call, miParse);
- }
- //implicit conversion can't be defined from or to object base class,
- //so we will check if object underlying type is one of the implicit converter of destType
- else if (origType == typeof (object)) {//test all implicit converter to destType on obj
- System.Reflection.Emit.Label emitTestNextImpOp;
- System.Reflection.Emit.Label emitImpOpFound = il.DefineLabel ();
- foreach (MethodInfo mi in destType.GetMethods (BindingFlags.Public | BindingFlags.Static)) {
- if (mi.Name == "op_Implicit") {
- if (mi.GetParameters () [0].ParameterType == destType)
- continue;
- emitTestNextImpOp = il.DefineLabel ();
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType);
- il.Emit (OpCodes.Brfalse, emitTestNextImpOp);
- if (mi.GetParameters () [0].ParameterType.IsValueType)
- il.Emit (OpCodes.Unbox_Any, mi.GetParameters () [0].ParameterType);
- else
- il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType);
-
- il.Emit (OpCodes.Call, mi);
- il.Emit (OpCodes.Br, emitImpOpFound);
-
- il.MarkLabel (emitTestNextImpOp);
- }
- }
- //il.Emit (OpCodes.Br, emitImpOpNotFound);
- il.MarkLabel (emitImpOpFound);
- } else {//search both orig and dest types for implicit operators
- MethodInfo miIO = getImplicitOp (origType, destType);
- if (miIO != null)
- il.Emit (OpCodes.Call, miIO);
- }
- }
- }
- }
- /// <summary>
- /// check type of current object on the stack and convert to dest type,
- /// use loc_0 so store it as object!!!
- /// </summary>
- internal static void emitConvert(ILGenerator il, Type dstType){
- System.Reflection.Emit.Label endConvert = il.DefineLabel ();
- System.Reflection.Emit.Label convert = il.DefineLabel ();
-
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Isinst, dstType);
- il.Emit (OpCodes.Brfalse, convert);
-
- if (dstType.IsValueType)
- il.Emit (OpCodes.Unbox_Any, dstType);
- else
- il.Emit (OpCodes.Isinst, dstType);
- il.Emit (OpCodes.Br, endConvert);
-
- il.MarkLabel (convert);
-
- if (dstType == typeof(string)) {
- System.Reflection.Emit.Label emitNullStr = il.DefineLabel ();
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Brfalse, emitNullStr);
- il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
- il.Emit (OpCodes.Br, endConvert);
- il.MarkLabel (emitNullStr);
- il.Emit (OpCodes.Pop);//remove null string from stack
- il.Emit (OpCodes.Ldstr, "");//replace with empty string
- } else if (dstType.IsPrimitive) {
- //il.Emit (OpCodes.Unbox_Any, dstType);
- MethodInfo miconv = CompilerServices.GetConvertMethod(dstType);
- if (miconv.IsStatic)
- il.Emit(OpCodes.Call, miconv);
- else
- il.Emit(OpCodes.Callvirt, miconv);
- } else if (dstType.IsValueType) {
- il.Emit (OpCodes.Unbox_Any, dstType);
- } else{
- il.Emit (OpCodes.Stloc_0); //save orig value in loc0
- //first check if not null
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Dup);
- il.Emit (OpCodes.Brfalse, endConvert);
- il.Emit (OpCodes.Callvirt, miGetType);
- il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing
- il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
- il.Emit (OpCodes.Call, miGetImplOp);
- il.Emit (OpCodes.Dup);
- convert = il.DefineLabel ();
- il.Emit (OpCodes.Brtrue, convert);
- il.Emit (OpCodes.Pop);
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Isinst, dstType);
- il.Emit (OpCodes.Br, endConvert);
-
- il.MarkLabel (convert);
- il.Emit (OpCodes.Ldnull);//null instance for invoke
- il.Emit (OpCodes.Ldc_I4_1);
- il.Emit(OpCodes.Newarr, typeof (object));
- il.Emit (OpCodes.Dup);//duplicate the array ref
- il.Emit (OpCodes.Ldc_I4_0);//push the index 0
- il.Emit (OpCodes.Ldloc_0);//push the orig value to convert
- il.Emit (OpCodes.Stelem, typeof (object));//set the array element at index 0
- il.Emit (OpCodes.Callvirt, miMIInvoke);
- }
-
- il.MarkLabel (endConvert);
- }
-
- /// <summary>
- /// Removes delegate from event handler by name
- /// </summary>
- static void removeEventHandlerByName(object instance, string eventName, string delegateName){
- Type t = instance.GetType ();
- FieldInfo fiEvt = getEventHandlerField (t, eventName);
- if (fiEvt == null) {
-#if DEBUG_BINDING
- Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance);
-#endif
- return;
- }
- EventInfo eiEvt = t.GetEvent (eventName);
- MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
- if (multiDel != null) {
- foreach (Delegate d in multiDel.GetInvocationList()) {
- if (d.Method.Name == delegateName) {
- eiEvt.RemoveEventHandler (instance, d);
-#if DEBUG_BINDING
- Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
-#endif
- }
- }
- }
- }
- /// <summary>
- /// Removes delegate from event handler by searching for the object they are bond to
- /// </summary>
- static void removeEventHandlerByTarget(object instance, string eventName, object target){
- Type t = instance.GetType ();
- FieldInfo fiEvt = getEventHandlerField (t, eventName);
- EventInfo eiEvt = t.GetEvent (eventName);
- MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
- if (multiDel != null) {
- foreach (Delegate d in multiDel.GetInvocationList()) {
- if (d.Target == target) {
- eiEvt.RemoveEventHandler (instance, d);
-#if DEBUG_BINDING
- Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
-#endif
- }
- }
- }
- }
- /// <summary>
- /// create delegate helper
- /// </summary>
- static Delegate createDel(object instance, Type eventType, string method){
- Type t = instance.GetType ();
- MethodInfo mi = t.GetMethod (method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- if (mi == null) {
- Debug.WriteLine ("Handler Method '{0}' not found in '{1}'", method, t);
- return null;
- }
- return Delegate.CreateDelegate (eventType, instance, mi);
- }
-
- internal static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){
-#if DEBUG_BINDING
- Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression);
-#endif
-
- Type lopType = null;
-
- if (currentNode == null)
- lopType = sourceEvent.DeclaringType;
- else
- lopType = currentNode.NodeType;
-
-#region Retrieve EventHandler parameter type
- MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke");
- ParameterInfo [] evtParams = evtInvoke.GetParameters ();
- Type handlerArgsType = evtParams [1].ParameterType;
-#endregion
-
- Type [] args = { typeof (object), handlerArgsType };
- DynamicMethod dm = new DynamicMethod ("dyn_eventHandler",
- typeof(void),
- args, true);
- ILGenerator il = dm.GetILGenerator (256);
- il.Emit (OpCodes.Nop);
-
- string [] srcLines = expression.Trim ().Split (new char [] { ';' });
-
- foreach (string srcLine in srcLines) {
- if (string.IsNullOrEmpty (srcLine))
- continue;
- string [] operandes = srcLine.Trim ().Split (new char [] { '=' });
- if (operandes.Length != 2) //not an affectation
- throw new NotSupportedException ();
-
- System.Reflection.Emit.Label cancel = il.DefineLabel ();
- System.Reflection.Emit.Label cancelFinalSet = il.DefineLabel ();
- System.Reflection.Emit.Label success = il.DefineLabel ();
-
- BindingMember lop = new BindingMember (operandes [0].Trim ());
- BindingMember rop = new BindingMember (operandes [1].Trim ());
-
- il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
-
-#region Left operande
- PropertyInfo lopPI = null;
-
- //in dyn handler, no datasource binding, so single name in expression are also handled as current node property
- if (lop.IsSingleName)
- lopPI = lopType.GetProperty (lop.Tokens [0]);
- else if (lop.IsCurrentNodeProperty)
- lopPI = lopType.GetProperty (lop.Tokens [1]);
- else
- lop.emitGetTarget (il, cancel);
-#endregion
-
-#region RIGHT OPERANDES
- if (rop.IsStringConstant){
- il.Emit (OpCodes.Ldstr, rop.Tokens[0]);
- lop.emitSetProperty (il);
- }else if (rop.IsSingleName && rop.Tokens[0] == "this"){
- il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
- lop.emitSetProperty (il);
- }else if (rop.LevelsUp ==0 && !string.IsNullOrEmpty(rop.Tokens[0])) {//parsable constant depending on lop type
- //if left operand is member of current node, it's easy to fetch type, else we should use reflexion in msil
- if (lopPI == null){//accept GraphicObj members, but it's restricive
- //TODO: we should get the parse method by reflexion, or something else
- lopPI = typeof(Widget).GetProperty (lop.Tokens [lop.Tokens.Length-1]);
- if (lopPI == null)
- throw new NotSupportedException ();
- }
-
- MethodInfo lopParseMi = CompilerServices.miParseEnum;
- if (lopPI.PropertyType.IsEnum){
- //load type of enum
- il.Emit(OpCodes.Ldtoken, lopPI.PropertyType);
- il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
- //load enum value name
- il.Emit (OpCodes.Ldstr, operandes [1].Trim ());
- //load false
- il.Emit (OpCodes.Ldc_I4_0);
- }else{
- lopParseMi = lopPI.PropertyType.GetMethod ("Parse");
- if (lopParseMi == null)
- throw new Exception (string.Format
- ("IML: no static 'Parse' method found in: {0}", lopPI.PropertyType.Name));
-
- il.Emit (OpCodes.Ldstr, operandes [1].Trim ());
- }
- if (lopParseMi.IsStatic)
- il.Emit (OpCodes.Call, lopParseMi);
- else
- il.Emit(OpCodes.Callvirt, lopParseMi);
- //il.Emit (OpCodes.Unbox_Any, lopPI.PropertyType);
- //emit left operand assignment
- il.Emit (OpCodes.Callvirt, lopPI.GetSetMethod());
- } else {//tree parsing and propert gets
- il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
-
- rop.emitGetTarget (il, cancelFinalSet);
- rop.emitGetProperty (il, cancelFinalSet);
- lop.emitSetProperty (il);
- }
-#endregion
-
- il.Emit (OpCodes.Br, success);
-
- il.MarkLabel (cancelFinalSet);
- il.Emit (OpCodes.Pop); //pop null MemberInfo on the stack causing cancelation
- il.MarkLabel (cancel);
- il.Emit (OpCodes.Pop); //pop null instance on the stack causing cancelation
- il.MarkLabel (success);
- }
-
- il.Emit (OpCodes.Ret);
-
- return dm.CreateDelegate (sourceEvent.EventHandlerType);
- }
-
- /// <summary>
- /// MSIL helper, go n levels up
- /// </summary>
- /// <returns><c>true</c>, if logical parents are not null</returns>
- /// <param name="instance">Start Instance</param>
- /// <param name="levelCount">Levels to go upward</param>
- internal static ILayoutable goUpNbLevels(ILayoutable instance, int levelCount){
- ILayoutable tmp = instance;
- int i = 0;
- while (tmp != null && i < levelCount) {
- tmp = tmp.LogicalParent;
- i++;
- }
- return tmp;
- }
- /// <summary>
- /// Splits expression on semicolon but ignore those between accolades
- /// </summary>
- internal static string[] splitOnSemiColumnOutsideAccolades (string expression){
- List<String> exps = new List<string>();
- int accCount = 0;
- int expPtr = 0;
- for (int c = 0; c < expression.Length; c++) {
- switch (expression[c]){
- case '{':
- accCount++;
- break;
- case '}':
- accCount--;
- break;
- case ';':
- if (accCount > 0)
- break;
- exps.Add(expression.Substring(expPtr, c - expPtr - 1));
- expPtr = c + 1;
- break;
- }
- }
- if (exps.Count == 0)
- exps.Add(expression);
- return exps.ToArray ();
- }
- /// <summary>
- /// Try to get the type named strDataType, search first in crow assembly then in
- /// entry assembly.
- /// </summary>
- /// <returns>the corresponding type object if found</returns>
- /// <param name="strDataType">type name</param>
- internal static Type getTypeFromName (string strDataType){
- if (knownTypes.ContainsKey (strDataType))
- return knownTypes [strDataType];
- Type dataType = Type.GetType(strDataType);
- if (dataType != null) {
- knownTypes.Add (strDataType, dataType);
- return dataType;
- }
- foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ()) {
- if (a.IsDynamic)
- continue;
- foreach (Type expT in a.GetExportedTypes ()) {
- if (expT.Name != strDataType && expT.FullName != strDataType)
- continue;
- if (!knownTypes.ContainsKey(strDataType))
- knownTypes.Add (strDataType, expT);
- return expT;
- }
- }
- knownTypes.Add (strDataType, null);
- return null;
- }
-
- //get value from member of object
- internal static object getDataTypeAndFetch (object data, string fetchMethod){
- Type dataType = data.GetType();
- //Console.WriteLine ($"get data type and fetch {data}.{fetchMethod}");
- MethodInfo miGetDatas = dataType.GetMethod (fetchMethod, new Type[] {});
- if (miGetDatas == null)
- miGetDatas = CompilerServices.SearchExtMethod (dataType, fetchMethod);
-
- if (miGetDatas == null) {//in last resort, search among properties
- PropertyInfo piDatas = dataType.GetProperty (fetchMethod);
- if (piDatas == null) {
- FieldInfo fiDatas = dataType.GetField (fetchMethod);
- if (fiDatas == null)//and among fields
- throw new Exception ("Fetch data member not found in ItemTemplate: " + fetchMethod);
- return fiDatas.GetValue (data);
- }
- miGetDatas = piDatas.GetGetMethod ();
- if (miGetDatas == null)
- throw new Exception ("Read only property for fetching data in ItemTemplate: " + fetchMethod);
- }
- return miGetDatas.IsStatic ?
- miGetDatas.Invoke (null, new object [] { data }) : miGetDatas.Invoke (data, null);
- }
- //TODO:memberinfo found here must be cached
- internal static object getValue (Type dataType, object data, string member)
- {
- //Console.WriteLine ($"get value: {dataType} ; {data} ; {member}");
-
- MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
- if (miGetDatas != null)
- return miGetDatas.Invoke (data, null);
- MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
- if (mbi == null) {
- MethodInfo miExt = CompilerServices.SearchExtMethod (dataType, member);
- if (miExt == null)//and among fields
- throw new Exception ($"member {member} not found in {dataType}");
- return miExt.Invoke (null, new object [] { data });
- }
- if (mbi.MemberType == MemberTypes.Property) {
- miGetDatas = (mbi as PropertyInfo)?.GetGetMethod ();
- if (miGetDatas == null)
- throw new Exception ($"no getter found for property {member} in {dataType}");
- return miGetDatas.Invoke (data, null);
- }
-
- FieldInfo fi = mbi as FieldInfo;
- if (fi == null)
- throw new Exception ($"member {member} not found in {dataType}");
-
- return fi.GetValue (data);
- }
- internal static MemberInfo GetMemberInfo (Type dataType, string member, out Type returnType)
- {
- MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
- if (miGetDatas != null) {
- returnType = miGetDatas.ReturnType;
- return miGetDatas;
- }
-
- MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
- if (mbi == null)
- miGetDatas = CompilerServices.SearchExtMethod (dataType, member);
- else {
- if (mbi is FieldInfo) {
- FieldInfo fi = mbi as FieldInfo;
- returnType = fi.FieldType;
- return mbi;
- }
- if (mbi.MemberType == MemberTypes.Property)
- miGetDatas = (mbi as PropertyInfo).GetGetMethod ();
- else
- miGetDatas = mbi as MethodInfo;
- }
- returnType = miGetDatas?.ReturnType;
- return miGetDatas;
-
- }
- internal static void emitGetMemberValue (ILGenerator il, Type dataType, MemberInfo mi)
- {
- switch (mi.MemberType) {
- case MemberTypes.Method:
- MethodInfo mim = mi as MethodInfo;
- if (mim.IsStatic)
- il.Emit (OpCodes.Call, mim);
- else
- il.Emit (OpCodes.Callvirt, mim);
- break;
- case MemberTypes.Field:
- il.Emit (OpCodes.Ldfld, mi as FieldInfo);
- break;
- }
- }
- //object is already on the stack
- internal static void emitGetMemberValue (ILGenerator il, Type dataType, string member)
- {
- MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
- if (miGetDatas != null) {
- il.Emit (OpCodes.Callvirt, miGetDatas);
- return;
- }
- MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
- if (mbi == null) {
- MethodInfo miExt = CompilerServices.SearchExtMethod (dataType, member);
- if (miExt == null)//and among fields
- throw new Exception ($"member {member} not found in {dataType}");
- il.Emit (OpCodes.Call, miExt);
- return;
- }
- if (mbi.MemberType == MemberTypes.Property) {
- miGetDatas = (mbi as PropertyInfo)?.GetGetMethod ();
- if (miGetDatas == null)
- throw new Exception ($"no getter found for property {member} in {dataType}");
- il.Emit (OpCodes.Callvirt, miGetDatas);
- return;
- }
-
- FieldInfo fi = mbi as FieldInfo;
- if (fi == null)
- throw new Exception ($"member {member} not found in {dataType}");
-
- il.Emit (OpCodes.Ldfld, fi);
- }
-
- //helper to get member info underlying type.
- internal static Type GetMemberInfoType (MemberInfo mi) =>
- mi.MemberType == MemberTypes.Field ? (mi as FieldInfo).FieldType :
- mi.MemberType == MemberTypes.Property ? (mi as PropertyInfo).PropertyType :
- mi.MemberType == MemberTypes.Method ? (mi as MethodInfo).ReturnType : null;
- }
-}
-
-//
-// ExtensionsMethods.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
using System.Linq.Expressions;
--- /dev/null
+//
+// BmpPicture.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using Crow.Cairo;
+
+namespace Crow
+{
+
+ /// <summary>
+ /// Derived from FILL for loading and drawing bitmaps in the interface
+ /// </summary>
+ public class BmpPicture : Picture
+ {
+ byte[] image = null;
+
+ #region CTOR
+ /// <summary>
+ /// Initializes a new instance of BmpPicture.
+ /// </summary>
+ public BmpPicture ()
+ {}
+ /// <summary>
+ /// Initializes a new instance of BmpPicture by loading the image pointed by the path argument
+ /// </summary>
+ /// <param name="path">image path, may be embedded</param>
+ public BmpPicture (string path) : base(path)
+ {
+ Load ();
+ }
+ #endregion
+ /// <summary>
+ /// load the image for rendering from the path given as argument
+ /// </summary>
+ /// <param name="path">image path, may be embedded</param>
+ void Load ()
+ {
+ if (sharedResources.ContainsKey (Path)) {
+ sharedPicture sp = sharedResources [Path];
+ image = (byte[])sp.Data;
+ Dimensions = sp.Dims;
+ return;
+ }
+ using (Stream stream = Interface.StaticGetStreamFromPath (Path)) {
+ using (StbImage stbi = new StbImage (stream)) {
+ image = new byte [stbi.Size];
+ //rgba to argb for cairo.
+ for (int i = 0; i < stbi.Size; i+=4) {
+ image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
+ image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
+ image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
+ image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
+ }
+ Dimensions = new Size (stbi.Width, stbi.Height);
+ }
+
+ //loadBitmap (new System.Drawing.Bitmap (stream));
+ }
+ sharedResources [Path] = new sharedPicture (image, Dimensions);
+ }
+
+
+
+ //load image via System.Drawing.Bitmap, cairo load png only
+ /*void loadBitmap (System.Drawing.Bitmap bitmap)
+ {
+ if (bitmap == null)
+ return;
+
+ System.Drawing.Imaging.BitmapData data = bitmap.LockBits
+ (new System.Drawing.Rectangle (0, 0, bitmap.Width, bitmap.Height),
+ System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ Dimensions = new Size (bitmap.Width, bitmap.Height);
+
+ int stride = data.Stride;
+ int bitmapSize = Math.Abs (data.Stride) * bitmap.Height;
+
+ image = new byte[bitmapSize];
+ System.Runtime.InteropServices.Marshal.Copy (data.Scan0, image, 0, bitmapSize);
+
+ bitmap.UnlockBits (data);
+ }*/
+
+ #region implemented abstract members of Fill
+
+ public override void SetAsSource (Context ctx, Rectangle bounds = default(Rectangle))
+ {
+ float widthRatio = 1f;
+ float heightRatio = 1f;
+
+ if (Scaled){
+ widthRatio = (float)bounds.Width / Dimensions.Width;
+ heightRatio = (float)bounds.Height / Dimensions.Height;
+ }
+
+ if (KeepProportions) {
+ if (widthRatio < heightRatio)
+ heightRatio = widthRatio;
+ else
+ widthRatio = heightRatio;
+ }
+
+ using (ImageSurface tmp = new ImageSurface (Format.Argb32, bounds.Width, bounds.Height)) {
+ using (Context gr = new Context (tmp)) {
+ gr.Translate (bounds.Left, bounds.Top);
+ gr.Scale (widthRatio, heightRatio);
+ gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
+
+ using (ImageSurface imgSurf = new ImageSurface (image, Format.Argb32,
+ Dimensions.Width, Dimensions.Height, 4 * Dimensions.Width)) {
+ gr.SetSourceSurface (imgSurf, 0,0);
+ gr.Paint ();
+ }
+ }
+ ctx.SetSource (tmp);
+ }
+ }
+ #endregion
+
+ /// <summary>
+ /// paint the image in the rectangle given in arguments according
+ /// to the Scale and keepProportion parameters.
+ /// </summary>
+ /// <param name="gr">drawing Backend context</param>
+ /// <param name="rect">bounds of the target surface to paint</param>
+ /// <param name="subPart">used for svg only</param>
+ public override void Paint (Context gr, Rectangle rect, string subPart = "")
+ {
+ float widthRatio = 1f;
+ float heightRatio = 1f;
+
+ if (Scaled){
+ widthRatio = (float)rect.Width / Dimensions.Width;
+ heightRatio = (float)rect.Height / Dimensions.Height;
+ }
+
+ if (KeepProportions) {
+ if (widthRatio < heightRatio)
+ heightRatio = widthRatio;
+ else
+ widthRatio = heightRatio;
+ }
+
+ gr.Save ();
+
+ gr.Translate (rect.Left,rect.Top);
+ gr.Scale (widthRatio, heightRatio);
+ gr.Translate ((rect.Width/widthRatio - Dimensions.Width)/2, (rect.Height/heightRatio - Dimensions.Height)/2);
+
+ using (ImageSurface imgSurf = new ImageSurface (image, Format.Argb32,
+ Dimensions.Width, Dimensions.Height, 4 * Dimensions.Width)) {
+ gr.SetSourceSurface (imgSurf, 0,0);
+ gr.Paint ();
+ }
+ gr.Restore ();
+ }
+ }
+}
+
s.EndsWith (".gif", true, System.Globalization.CultureInfo.InvariantCulture))
return Picture.Parse (s);
- return (SolidColor)SolidColor.Parse (s);
+ return new SolidColor((Color)Color.Parse (s));
}
public static implicit operator Color(Fill c){
SolidColor sc = c as SolidColor;
- return sc == null ? default(Color) : sc.color;
+ return sc == null ? default : sc.color;
}
public static implicit operator Fill(Color c){
return new SolidColor (c);
}
-
}
}
--- /dev/null
+//
+// Picture.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using Crow.Cairo;
+using System.Collections.Generic;
+
+namespace Crow
+{
+ /// <summary>
+ /// store data and dimensions for resource sharing
+ /// </summary>
+ internal class sharedPicture {
+ //TODO: restructure this whith clever conceptual classes
+ public object Data;
+ public Size Dims;
+ public sharedPicture (object _data, Size _dims){
+ Data = _data;
+ Dims = _dims;
+ }
+ }
+ /// <summary>
+ /// virtual class for loading and drawing picture in the interface
+ ///
+ /// Every loaded resources are stored in a dictonary with their path as key and shared
+ /// among interface elements
+ /// </summary>
+ public abstract class Picture : Fill
+ {
+ /// <summary>
+ /// share a single store for picture resources among usage in different controls
+ /// </summary>
+ internal static Dictionary<string, sharedPicture> sharedResources = new Dictionary<string, sharedPicture>();
+
+ /// <summary>
+ /// path of the picture
+ /// </summary>
+ public string Path;
+ /// <summary>
+ /// unscaled dimensions fetched on loading
+ /// </summary>
+ public Size Dimensions;
+ /// <summary>
+ /// if true and image has to be scalled, it will be scaled in both direction
+ /// equaly
+ /// </summary>
+ public bool KeepProportions = false;
+ /// <summary>
+ /// allow or not the picture to be scalled on request by the painter
+ /// </summary>
+ public bool Scaled = true;
+
+ #region CTOR
+ /// <summary>
+ /// Initializes a new instance of Picture.
+ /// </summary>
+ public Picture ()
+ {
+ }
+ /// <summary>
+ /// Initializes a new instance of Picture by loading the image pointed by the path argument
+ /// </summary>
+ /// <param name="path">image path, may be embedded</param>
+ public Picture (string path)
+ {
+ Path = path;
+ }
+ #endregion
+
+ #region Image Loading
+ /// <summary>
+ /// load the image for rendering from the stream given as argument
+ /// </summary>
+ /// <param name="stream">picture stream</param>
+ //public abstract void Load(Interface iface, string path);
+ #endregion
+
+ /// <summary>
+ /// abstract method to paint the image in the rectangle given in arguments according
+ /// to the Scale and keepProportion parameters.
+ /// </summary>
+ /// <param name="gr">drawing Backend context</param>
+ /// <param name="rect">bounds of the target surface to paint</param>
+ /// <param name="subPart">used for svg only</param>
+ public abstract void Paint(Context ctx, Rectangle rect, string subPart = "");
+
+ #region Operators
+ public static implicit operator Picture(string path)
+ {
+ if (string.IsNullOrEmpty (path))
+ return null;
+
+ Picture _pic = null;
+
+ if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
+ _pic = new SvgPicture (path);
+ else
+ _pic = new BmpPicture (path);
+
+ return _pic;
+ }
+ public static implicit operator string(Picture _pic)
+ {
+ return _pic == null ? null : _pic.Path;
+ }
+ #endregion
+
+ public static new object Parse(string path)
+ {
+ if (string.IsNullOrEmpty (path))
+ return null;
+
+ Picture _pic = null;
+
+ if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
+ _pic = new SvgPicture (path);
+ else
+ _pic = new BmpPicture (path);
+
+ return _pic;
+ }
+ public override string ToString ()
+ {
+ return Path;
+ }
+ }
+}
+
--- /dev/null
+//
+// SolidColor.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Serialization;
+using System.Reflection;
+using System.Diagnostics;
+using Crow.Cairo;
+
+
+
+namespace Crow
+{
+ public class SolidColor : Fill
+ {
+ public Color color = Color.Transparent;
+ #region CTOR
+ public SolidColor(Color c)
+ {
+ color = c;
+ }
+ #endregion
+
+ #region implemented abstract members of Fill
+ public override void SetAsSource (Context ctx, Rectangle bounds = default)
+ {
+ ctx.SetSourceRGBA (color.R, color.G, color.B, color.A);
+ }
+ public static new object Parse(string s)
+ {
+ return new SolidColor((Color)s);
+ }
+ #endregion
+
+ #region Operators
+ public static implicit operator Color(SolidColor c) => c.color;
+ public static implicit operator SolidColor(Color c) => new SolidColor (c);
+
+ public static bool operator ==(SolidColor left, SolidColor right) => left?.color == right?.color;
+ public static bool operator !=(SolidColor left, SolidColor right) => left?.color != right?.color;
+
+ public override int GetHashCode ()
+ {
+ return color.GetHashCode();
+ }
+ public override bool Equals (object obj)
+ {
+ if (obj is Color)
+ return color == (Color)obj;
+ if (obj is SolidColor)
+ return color == (obj as SolidColor).color;
+ return false;
+ }
+// public static bool operator ==(SolidColor c, string n)
+// {
+// return c.color.Name == n ? true : false;
+// }
+// public static bool operator !=(SolidColor c, string n)
+// {
+// return c.color.Name == n ? false : true;
+// }
+// public static bool operator ==(string n, SolidColor c)
+// {
+// return c.color.Name == n ? true : false;
+// }
+// public static bool operator !=(string n, SolidColor c)
+// {
+// return c.color.Name == n ? false : true;
+// }
+ public static SolidColor operator *(SolidColor c, Double f)
+ {
+ return new SolidColor(new Color(c.color.R,c.color.G,c.color.B,c.color.A * f));
+ }
+ public static SolidColor operator +(SolidColor c1, SolidColor c2)
+ {
+ return new SolidColor(new Color(c1.color.R + c2.color.R,c1.color.G + c2.color.G,c1.color.B + c2.color.B,c1.color.A + c2.color.A));
+ }
+ public static SolidColor operator -(SolidColor c1, SolidColor c2)
+ {
+ return new SolidColor(new Color(c1.color.R - c2.color.R,c1.color.G - c2.color.G,c1.color.B - c2.color.B,c1.color.A - c2.color.A));
+ }
+ #endregion
+
+ public override string ToString()
+ {
+ return color.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// SvgPicture.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// Derived from FILL for loading and drawing SVG images in the interface
+ /// </summary>
+ public class SvgPicture : Picture
+ {
+ Rsvg.Handle hSVG;
+
+ #region CTOR
+ /// <summary>
+ /// Initializes a new instance of SvgPicture.
+ /// </summary>
+ public SvgPicture ()
+ {}
+ /// <summary>
+ /// Initializes a new instance of SvgPicture by loading the SVG file pointed by the path argument
+ /// </summary>
+ /// <param name="path">image path, may be embedded</param>
+ public SvgPicture (string path) : base(path)
+ {
+ Load ();
+ }
+ #endregion
+
+ void Load ()
+ {
+ if (sharedResources.ContainsKey (Path)) {
+ sharedPicture sp = sharedResources [Path];
+ hSVG = (Rsvg.Handle)sp.Data;
+ Dimensions = sp.Dims;
+ return;
+ }
+ using (Stream stream = Interface.StaticGetStreamFromPath (Path)) {
+ using (MemoryStream ms = new MemoryStream ()) {
+ stream.CopyTo (ms);
+
+ hSVG = new Rsvg.Handle (ms.ToArray ());
+ Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height);
+ }
+ }
+ sharedResources [Path] = new sharedPicture (hSVG, Dimensions);
+ }
+
+ public void LoadSvgFragment (string fragment) {
+ hSVG = new Rsvg.Handle (System.Text.Encoding.Unicode.GetBytes(fragment));
+ Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height);
+ }
+
+ #region implemented abstract members of Fill
+
+ public override void SetAsSource (Context ctx, Rectangle bounds = default(Rectangle))
+ {
+ float widthRatio = 1f;
+ float heightRatio = 1f;
+
+ if (Scaled){
+ widthRatio = (float)bounds.Width / Dimensions.Width;
+ heightRatio = (float)bounds.Height / Dimensions.Height;
+ }
+
+ if (KeepProportions) {
+ if (widthRatio < heightRatio)
+ heightRatio = widthRatio;
+ else
+ widthRatio = heightRatio;
+ }
+
+ using (ImageSurface tmp = new ImageSurface (Format.Argb32, bounds.Width, bounds.Height)) {
+ using (Context gr = new Context (tmp)) {
+ gr.Translate (bounds.Left, bounds.Top);
+ gr.Scale (widthRatio, heightRatio);
+ gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
+
+ hSVG.RenderCairo (gr);
+ }
+ ctx.SetSource (tmp);
+ }
+ }
+ #endregion
+
+ /// <summary>
+ /// paint the image in the rectangle given in arguments according
+ /// to the Scale and keepProportion parameters.
+ /// </summary>
+ /// <param name="gr">drawing Backend context</param>
+ /// <param name="rect">bounds of the target surface to paint</param>
+ /// <param name="subPart">limit rendering to svg part named 'subPart'</param>
+ public override void Paint (Context gr, Rectangle rect, string subPart = "")
+ {
+ if (hSVG == null)
+ return;
+ float widthRatio = 1f;
+ float heightRatio = 1f;
+
+ if (Scaled) {
+ widthRatio = (float)rect.Width / Dimensions.Width;
+ heightRatio = (float)rect.Height / Dimensions.Height;
+ }
+ if (KeepProportions) {
+ if (widthRatio < heightRatio)
+ heightRatio = widthRatio;
+ else
+ widthRatio = heightRatio;
+ }
+
+ gr.Save ();
+
+ gr.Translate (rect.Left,rect.Top);
+ gr.Scale (widthRatio, heightRatio);
+ gr.Translate (((float)rect.Width/widthRatio - Dimensions.Width)/2f, ((float)rect.Height/heightRatio - Dimensions.Height)/2f);
+
+ if (string.IsNullOrEmpty (subPart))
+ hSVG.RenderCairo (gr);
+ else
+ hSVG.RenderCairoSub (gr, "#" + subPart);
+
+ gr.Restore ();
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2020 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.Reflection.Emit;
+using System.Reflection;
+using System.Diagnostics;
+using System.Linq;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Xml;
+using Crow.IML;
+using System.Text;
+
+namespace Crow.IML
+{
+ public static class CompilerServices
+ {
+ /// <summary>
+ /// known types cache, prevent rewalking all the assemblies of the domain
+ /// the key is the type simple name
+ /// </summary>
+ internal static Dictionary<string, Type> knownTypes = new Dictionary<string, Type> ();
+ /// <summary>
+ /// known extension methods.
+ /// key is type dot memberName.
+ /// </summary>
+ internal static Dictionary<string, MethodInfo> knownExtMethods = new Dictionary<string, MethodInfo> ();
+
+ internal static MethodInfo stringEquals = typeof (string).GetMethod("Equals", new Type [3] { typeof (string), typeof (string), typeof (StringComparison) });
+ internal static MethodInfo miObjToString = typeof(object).GetMethod("ToString");
+ internal static MethodInfo miGetType = typeof(object).GetMethod("GetType");
+ internal static MethodInfo miParseEnum = typeof(Enum).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
+ Type.DefaultBinder, new Type [] {typeof (Type), typeof (string), typeof (bool)}, null);
+
+ internal static MethodInfo miGetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
+ internal static MethodInfo miGetEvent = typeof(Type).GetMethod("GetEvent", new Type[] {typeof(string)});
+
+ internal static MethodInfo miMIInvoke = typeof(MethodInfo).GetMethod ("Invoke", new Type[] {
+ typeof(object),
+ typeof(object[])
+ });
+
+ internal static MethodInfo miCreateBoundDel = typeof(Delegate).GetMethod ("CreateDelegate", new Type[] { typeof(Type), typeof(object), typeof(MethodInfo) });//create bound delegate
+ internal static MethodInfo miGetColCount = typeof(System.Collections.ICollection).GetProperty("Count").GetGetMethod();
+ internal static MethodInfo miGetDelegateListItem = typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) });
+
+ internal static MethodInfo miCompileDynEventHandler = typeof(CompilerServices).GetMethod ("compileDynEventHandler", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miRemEvtHdlByName = typeof(CompilerServices).GetMethod("removeEventHandlerByName", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miRemEvtHdlByTarget = typeof(CompilerServices).GetMethod("removeEventHandlerByTarget", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetMethInfoWithRefx = typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetMembIinfoWithRefx = typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miSetValWithRefx = typeof(CompilerServices).GetMethod("setValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetValWithRefx = typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miCreateDel = typeof(CompilerServices).GetMethod ("createDel", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetDataTypeAndFetch = typeof(CompilerServices).GetMethod("getDataTypeAndFetch", BindingFlags.Static | BindingFlags.NonPublic);
+
+
+ internal static MethodInfo miGoUpLevels = typeof(CompilerServices).GetMethod("goUpNbLevels", BindingFlags.Static | BindingFlags.NonPublic);
+
+ internal static FieldInfo fiCachedDel = typeof(Instantiator).GetField("cachedDelegates", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static FieldInfo fiTemplateBinding = typeof(Instantiator).GetField("templateBinding", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miDSChangeEmitHelper = typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miDSReverseBinding = typeof(Instantiator).GetMethod("dataSourceReverseBinding", BindingFlags.Static | BindingFlags.NonPublic);
+
+ internal static FieldInfo miSetCurIface = typeof(Widget).GetField ("IFace", BindingFlags.Public | BindingFlags.Instance);
+ internal static MethodInfo miFindByName = typeof (Widget).GetMethod ("FindByName");
+ internal static MethodInfo miGetGObjItem = typeof(List<Widget>).GetMethod("get_Item", new Type[] { typeof(Int32) });
+ internal static MethodInfo miLoadDefaultVals = typeof (Widget).GetMethod ("loadDefaultValues");
+ internal static PropertyInfo piStyle = typeof (Widget).GetProperty ("Style");
+ internal static MethodInfo miGetLogicalParent = typeof(Widget).GetProperty("LogicalParent").GetGetMethod();
+ internal static MethodInfo miGetDataSource = typeof(Widget).GetProperty("DataSource").GetGetMethod ();
+ internal static EventInfo eiLogicalParentChanged = typeof(Widget).GetEvent("LogicalParentChanged");
+
+ internal static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("CreateInstance", BindingFlags.Instance | BindingFlags.Public);
+ internal static MethodInfo miIFaceCreateTemplateInst = typeof (Interface).GetMethod ("CreateTemplateInstance", BindingFlags.Instance | BindingFlags.Public);
+ internal static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate", BindingFlags.Instance | BindingFlags.Public);
+
+ internal static MethodInfo miAddITemp = typeof(Dictionary<string, ItemTemplate>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) });
+ internal static MethodInfo miGetITempFromDic = typeof(Dictionary<string, ItemTemplate>).GetMethod ("get_Item", new Type[] { typeof(string) });
+ internal static FieldInfo fldItemTemplates = typeof(TemplatedGroup).GetField("ItemTemplates");
+ internal static MethodInfo miLoadPage = typeof(TemplatedGroup).GetMethod ("loadPage", BindingFlags.Instance | BindingFlags.NonPublic| BindingFlags.Public);
+ internal static MethodInfo miIsAlreadyExpanded = typeof(TemplatedGroup).GetMethod("emitHelperIsAlreadyExpanded", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ internal static MethodInfo miCreateExpDel = typeof(ItemTemplate).GetMethod ("CreateExpandDelegate");
+ internal static FieldInfo fiFetchMethodName = typeof(ItemTemplate).GetField("fetchMethodName", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ #if DESIGN_MODE
+ internal static MethodInfo miDicStrStrAdd = typeof(Dictionary<string, string>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(string) });
+ #endif
+
+ #region tree handling methods
+ internal static FieldInfo fiChild = typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miSetChild = typeof (Container).GetMethod ("SetChild");
+ internal static MethodInfo miAddChild = typeof (Group).GetMethod ("AddChild");
+ internal static FieldInfo fiChildren = typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miLoadTmp = typeof (TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static PropertyInfo piContent = typeof(TemplatedContainer).GetProperty ("Content");
+ internal static MethodInfo miAddItem = typeof (TemplatedGroup).GetMethod ("AddItem", BindingFlags.Instance | BindingFlags.Public);
+ internal static MethodInfo miGetItems = typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ();
+ #endregion
+
+ #region ValueChange & DSChange Reflexion member info
+ internal static EventInfo eiValueChange = typeof (IValueChange).GetEvent ("ValueChanged");
+ internal static MethodInfo miInvokeValueChange = eiValueChange.EventHandlerType.GetMethod ("Invoke");
+ internal static Type [] argsBoundValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static Type [] argsValueChange = { typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static FieldInfo fiVCNewValue = typeof (ValueChangeEventArgs).GetField ("NewValue");
+ internal static FieldInfo fiVCMbName = typeof (ValueChangeEventArgs).GetField ("MemberName");
+
+ internal static EventInfo eiDSChange = typeof (Widget).GetEvent ("DataSourceChanged");
+ internal static MethodInfo miInvokeDSChange = eiDSChange.EventHandlerType.GetMethod ("Invoke");
+ internal static Type [] argsBoundDSChange = {typeof (object), typeof (object), miInvokeDSChange.GetParameters () [1].ParameterType };
+ internal static FieldInfo fiDSCNewDS = typeof (DataSourceChangeEventArgs).GetField ("NewDataSource");
+ internal static FieldInfo fiDSCOldDS = typeof (DataSourceChangeEventArgs).GetField ("OldDataSource");
+ internal static Type ehTypeDSChange = eiDSChange.EventHandlerType;
+ #endregion
+
+ /// <summary>
+ /// Loc0 is the current graphic object and arg2 of loader is the current interface
+ /// </summary>
+ /// <param name="il">Il.</param>
+ public static void emitSetCurInterface(ILGenerator il){
+ il.Emit (OpCodes.Ldloc_0);
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Stfld, miSetCurIface);
+ }
+
+ public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){
+ il.Emit (OpCodes.Ldloc_0);
+
+ if (val == null) {
+ il.Emit (OpCodes.Ldnull);
+ il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
+ return;
+ }
+ Type dvType = val.GetType ();
+
+ if (dvType.IsValueType) {
+ if (pi.PropertyType.IsValueType) {
+ if (pi.PropertyType.IsEnum) {
+ if (pi.PropertyType != dvType)
+ throw new Exception ("Enum mismatch in default values: " + pi.PropertyType.FullName);
+ il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val));
+ } else {
+ switch (Type.GetTypeCode (dvType)) {
+ case TypeCode.Boolean:
+ if ((bool)val == true)
+ il.Emit (OpCodes.Ldc_I4_1);
+ else
+ il.Emit (OpCodes.Ldc_I4_0);
+ break;
+// case TypeCode.Empty:
+// break;
+// case TypeCode.Object:
+// break;
+// case TypeCode.DBNull:
+// break;
+// case TypeCode.SByte:
+// break;
+// case TypeCode.Decimal:
+// break;
+// case TypeCode.DateTime:
+// break;
+ case TypeCode.Char:
+ il.Emit (OpCodes.Ldc_I4, Convert.ToChar (val));
+ break;
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val));
+ break;
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ il.Emit (OpCodes.Ldc_I4, Convert.ToUInt32 (val));
+ break;
+ case TypeCode.Int64:
+ il.Emit (OpCodes.Ldc_I8, Convert.ToInt64 (val));
+ break;
+ case TypeCode.UInt64:
+ il.Emit (OpCodes.Ldc_I8, Convert.ToUInt64 (val));
+ break;
+ case TypeCode.Single:
+ il.Emit (OpCodes.Ldc_R4, Convert.ToSingle (val));
+ break;
+ case TypeCode.Double:
+ il.Emit (OpCodes.Ldc_R8, Convert.ToDouble (val));
+ break;
+ case TypeCode.String:
+ il.Emit (OpCodes.Ldstr, Convert.ToString (val));
+ break;
+ default:
+ il.Emit (OpCodes.Pop);
+ return;
+ }
+ }
+ } else
+ throw new Exception ("Expecting valuetype in default values for: " + pi.Name);
+ }else{
+ //surely a class or struct
+ if (dvType != typeof(string))
+ throw new Exception ("Expecting String in default values for: " + pi.Name);
+ if (pi.PropertyType == typeof(string))
+ il.Emit (OpCodes.Ldstr, Convert.ToString (val));
+ else if (pi.PropertyType.IsEnum) {
+ //load type of enum
+ il.Emit(OpCodes.Ldtoken, pi.PropertyType);
+ il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ //load enum value name
+ il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:implement here string format?
+ //load false
+ il.Emit (OpCodes.Ldc_I4_0);
+ il.Emit (OpCodes.Call, CompilerServices.miParseEnum);
+
+ if (CompilerServices.miParseEnum.ReturnType != pi.PropertyType)
+ il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
+ } else {
+ MethodInfo miParse = pi.PropertyType.GetMethod
+ ("Parse", BindingFlags.Static | BindingFlags.Public,
+ Type.DefaultBinder, new Type [] {typeof (string)},null);
+ if (miParse == null)
+ throw new Exception ("no Parse method found for: " + pi.PropertyType.FullName);
+
+ il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:is this convert required?
+ il.Emit (OpCodes.Call, miParse);
+
+ if (miParse.ReturnType != pi.PropertyType)
+ il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
+ }
+ }
+ il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
+ }
+
+ #region conversions
+
+ internal static MethodInfo GetConvertMethod (Type targetType)
+ {
+ string name;
+
+ if (targetType == typeof (bool))
+ name = "ToBoolean";
+ else if (targetType == typeof (byte))
+ name = "ToByte";
+ else if (targetType == typeof (short))
+ name = "ToInt16";
+ else if (targetType == typeof (int))
+ name = "ToInt32";
+ else if (targetType == typeof (uint))
+ name = "ToUInt32";
+ else if (targetType == typeof (long))
+ name = "ToInt64";
+ else if (targetType == typeof (double))
+ name = "ToDouble";
+ else if (targetType == typeof (float))
+ name = "ToSingle";
+ else if (targetType == typeof (string))
+ return typeof (object).GetMethod ("ToString", Type.EmptyTypes);
+ else //try to find implicit convertion
+ throw new NotImplementedException (string.Format ("Conversion to {0} is not implemented.", targetType.Name));
+
+ return typeof (Convert).GetMethod (name, BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (object) }, null);
+ }
+ #endregion
+
+ #region Reflexion helpers
+ static MemberInfo getMemberInfoWithReflexion(object instance, string member){
+ Type t = instance.GetType();
+#if DEBUG_BINDING_FUNC_CALLS
+ Console.WriteLine ($"getMemberInfoWithReflexion ({instance},{member}); type:{t}");
+#endif
+ MemberInfo mi = t.GetMember (member)?.FirstOrDefault();
+ if (mi == null)
+ mi = CompilerServices.SearchExtMethod (t, member);
+ return mi;
+ }
+ static MethodInfo getMethodInfoWithReflexion(object instance, string method){
+#if DEBUG_BINDING_FUNC_CALLS
+ Console.WriteLine ($"getMethodInfoWithReflexion ({instance},{method}); type:{instance.GetType ()}");
+#endif
+ return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+ }
+ /// <summary>
+ /// set value, convert if required
+ /// </summary>
+ /// <param name="dest">Destination instance</param>
+ /// <param name="value">Value</param>
+ /// <param name="destMember">Destination member</param>
+ static void setValueWithReflexion(object dest, object value, string destMember){
+#if DEBUG_BINDING_FUNC_CALLS
+ Console.WriteLine ($"setValueWithReflexion (dest:{dest},value:{value},member:{destMember});");
+#endif
+ Type destType = null;
+ Type origType = null;
+ object convertedVal = null;
+
+ MemberInfo miDest = getMemberInfoWithReflexion (dest, destMember);
+
+ if (miDest == null) {
+ Debug.WriteLine ("Reverse template binding error: " + destMember + " not found in " + dest);
+ return;
+ }
+
+ destType = CompilerServices.GetMemberInfoType (miDest);
+
+ try {
+ if (value != null) {
+ if (destType == typeof (object))//TODO: check that test of destType is not causing problems
+ convertedVal = value;
+ else {
+ origType = value.GetType ();
+ if (destType.IsAssignableFrom (origType))
+ convertedVal = Convert.ChangeType (value, destType);
+ else if (origType == typeof(string) & destType.IsPrimitive)
+ convertedVal = Convert.ChangeType(value, destType);
+ else if (origType.IsPrimitive & destType.IsPrimitive)
+ convertedVal = GetConvertMethod (destType).Invoke (null, new Object[] { value });
+ else
+ convertedVal = getImplicitOp (origType, destType).Invoke (value, null);
+ }
+ }
+ } catch (Exception ex) {
+ Debug.WriteLine (ex.ToString ());
+ return;
+ }
+
+ if (miDest.MemberType == MemberTypes.Property)
+ (miDest as PropertyInfo).SetValue (dest, convertedVal);
+ else if (miDest.MemberType == MemberTypes.Field)
+ (miDest as FieldInfo).SetValue (dest, convertedVal);
+ }
+ /// <summary>
+ /// Gets value with reflexion, return empty string ("") for string and object and return
+ /// default value for valueType data.
+ /// </summary>
+ static object getValueWithReflexion(object instance, MemberInfo mi){
+#if DEBUG_BINDING_FUNC_CALLS
+ Console.WriteLine ($"getValueWithReflexion ({instance},{mi});");
+#endif
+ object tmp = null;
+ Type dstType = null;
+ if (mi == null)
+ return null;
+ try {
+ if (mi.MemberType == MemberTypes.Property) {
+ PropertyInfo pi = mi as PropertyInfo;
+ tmp = pi.GetValue (instance);
+ dstType = pi.PropertyType;
+ }else if (mi.MemberType == MemberTypes.Field) {
+ FieldInfo fi = mi as FieldInfo;
+ tmp = fi.GetValue (instance);
+ dstType = fi.FieldType;
+ }else if (mi.MemberType == MemberTypes.Method) {
+ MethodInfo gi = mi as MethodInfo;
+ if (gi.IsStatic)
+ tmp = gi.Invoke(null, new object[] {instance});
+ else
+ tmp = gi.Invoke(instance, null);
+ dstType = gi.ReturnType;
+ }
+ if (tmp != null)
+ return tmp;
+ if (dstType == typeof(string) || dstType == typeof (object))//TODO:object should be allowed to return null and not ""
+ return "";
+ if (dstType.IsValueType)
+ return Activator.CreateInstance (dstType);
+ } catch (Exception ex) {
+ Debug.WriteLine (ex.ToString ());
+ return "";
+ }
+
+ return null;
+ }
+ internal static MethodInfo SearchExtMethod (Type t, string methodName)
+ {
+ string key = t.Name + "." + methodName;
+ if (knownExtMethods.ContainsKey (key))
+ return knownExtMethods [key];
+
+ //Console.WriteLine ($"*** search extension method: {t};{methodName} => key={key}");
+
+ MethodInfo mi = null;
+ mi = GetExtensionMethods (Assembly.GetEntryAssembly (), t, methodName);
+ if (mi == null)
+ mi = GetExtensionMethods (t.Module.Assembly, t, methodName);
+
+ //add key even if mi is null to prevent searching again and again for propertyless bindings
+ knownExtMethods.Add (key, mi);
+ return mi;
+ }
+
+ public static MethodInfo GetExtensionMethods (Assembly assembly, Type extendedType, string methodName)
+ {
+ foreach (Type t in assembly.GetTypes ().Where
+ (ty => ty.IsDefined (typeof (ExtensionAttribute), false))) {
+ foreach (MethodInfo mi in t.GetMethods
+ (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Where
+ (m=> m.Name == methodName && m.IsDefined (typeof (ExtensionAttribute), false) &&
+ m.GetParameters ().Length == 1)) {
+ Type curType = extendedType;
+ while (curType != null) {
+ if (mi.GetParameters () [0].ParameterType == curType)
+ return mi;
+ curType = curType.BaseType;
+ }
+ }
+
+ }
+ return null;
+ }
+ /// <summary>
+ /// retrieve event handler in class or ancestors
+ /// </summary>
+ static FieldInfo getEventHandlerField (Type type, string eventName)
+ {
+ FieldInfo fi;
+ Type ty = type;
+ do {
+ fi = ty.GetField (eventName,
+ BindingFlags.NonPublic |
+ BindingFlags.Instance |
+ BindingFlags.GetField);
+ ty = ty.BaseType;
+ if (ty == null)
+ break;
+ } while (fi == null);
+ return fi;
+ }
+ /// <summary>
+ /// search for an implicit conversion method in origine or destination classes
+ /// </summary>
+ static MethodInfo getImplicitOp(Type origType, Type dstType){
+ foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
+ if (mi.Name == "op_Implicit") {
+ if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
+ return mi;
+ }
+ }
+ foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
+ if (mi.Name == "op_Implicit") {
+ if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
+ return mi;
+ }
+ }
+ return null;
+ }
+ #endregion
+
+ /// <summary>
+ /// Emits tree parsing command to fetch dest instance starting from orig node
+ /// </summary>
+ internal static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){
+ int ptr = 0;
+ while (orig [ptr] == dest [ptr]) {
+ ptr++;
+ if (ptr == orig.Count || ptr == dest.Count)
+ break;
+ }
+ for (int i = 0; i < orig.Count - ptr; i++)
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetLogicalParent);
+ while (ptr < dest.Count) {
+ emitGetChild (il, dest [ptr-1].CrowType, dest [ptr].Index);
+ ptr++;
+ }
+ }
+ /// <summary>
+ /// Emits tree parsing commands to get child starting at root node
+ /// </summary>
+ /// <param name="il">MSIL generator</param>
+ /// <param name="dest">Absolute Node Address of the instance to get</param>
+ internal static void emitGetInstance (ILGenerator il, NodeAddress dest){
+ if (dest == null)
+ return;
+ for (int i = 0; i < dest.Count - 1; i++)
+ emitGetChild (il, dest [i].CrowType, dest [i + 1].Index);
+ }
+ /// <summary>
+ /// Emits msil to fetch chil instance of current GraphicObject on the stack
+ /// </summary>
+ /// <param name="il">Il generator</param>
+ /// <param name="parentType">Parent type</param>
+ /// <param name="index">Index of child, -1 for template root</param>
+ internal static void emitGetChild(ILGenerator il, Type parentType, int index){
+ if (typeof (Group).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Ldfld, fiChildren);
+ il.Emit(OpCodes.Ldc_I4, index);
+ il.Emit (OpCodes.Callvirt, miGetGObjItem);
+ return;
+ }
+ if (typeof(Container).IsAssignableFrom (parentType) || index < 0) {
+ il.Emit (OpCodes.Ldfld, fiChild);
+ return;
+ }
+ if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Callvirt, piContent.GetGetMethod());
+ return;
+ }
+ if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Callvirt, miGetItems);
+ il.Emit(OpCodes.Ldc_I4, index);
+ il.Emit (OpCodes.Callvirt, miGetGObjItem);
+ return;
+ }
+ }
+
+ /// <summary>
+ /// Emit MSIL for conversion from orig type to dest type
+ /// </summary>
+ internal static void emitConvert(ILGenerator il, Type origType, Type destType){
+ if (destType == typeof(object))
+ return;
+ if (destType == typeof (string)) {
+ System.Reflection.Emit.Label emitNullStr = il.DefineLabel ();
+ System.Reflection.Emit.Label endConvert = il.DefineLabel ();
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Brfalse, emitNullStr);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ il.Emit (OpCodes.Br, endConvert);
+ il.MarkLabel (emitNullStr);
+ il.Emit (OpCodes.Pop);//remove null string from stack
+ il.Emit (OpCodes.Ldstr, "");//replace with empty string
+ il.MarkLabel (endConvert);
+ } else if ((origType.IsEnum || origType == typeof (Enum)) && destType.IsEnum) {//TODO:double check this (multiple IsEnum test, no check of enum underlying type
+ il.Emit (OpCodes.Unbox_Any, destType);
+ return;
+ } else if (origType.IsValueType) {
+ if (destType != origType) {
+ MethodInfo miIO = getImplicitOp (origType, destType);
+ if (miIO != null) {
+ System.Reflection.Emit.Label emitCreateDefault = il.DefineLabel ();
+ System.Reflection.Emit.Label emitContinue = il.DefineLabel ();
+ LocalBuilder lbStruct = il.DeclareLocal (origType);
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Brfalse, emitCreateDefault);
+ il.Emit (OpCodes.Unbox_Any, origType);
+ il.Emit (OpCodes.Br, emitContinue);
+ il.MarkLabel (emitCreateDefault);
+ il.Emit (OpCodes.Pop);//pop null value
+ il.Emit (OpCodes.Ldloca, lbStruct);
+ il.Emit (OpCodes.Initobj, origType);
+ il.Emit (OpCodes.Ldloc, lbStruct);
+ il.MarkLabel (emitContinue);
+ il.Emit (OpCodes.Call, miIO);
+ } else {
+ MethodInfo miconv = CompilerServices.GetConvertMethod (destType);
+ if (miconv.IsStatic)
+ il.Emit (OpCodes.Call, miconv);
+ else
+ il.Emit (OpCodes.Callvirt, miconv);
+ }
+ } else
+ il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this
+ } else {
+ if (destType.IsAssignableFrom (origType))
+ il.Emit (OpCodes.Castclass, destType);
+ else {
+ if (origType == typeof (string)) {
+ //search dest type for parse method
+ MethodInfo miParse = destType.GetMethod
+ ("Parse", BindingFlags.Static | BindingFlags.Public,
+ Type.DefaultBinder, new Type [] { typeof (string) }, null);
+ if (miParse == null)
+ throw new Exception ("no Parse method found for: " + destType.FullName);
+ il.Emit (OpCodes.Call, miParse);
+ }
+ //implicit conversion can't be defined from or to object base class,
+ //so we will check if object underlying type is one of the implicit converter of destType
+ else if (origType == typeof (object)) {//test all implicit converter to destType on obj
+ System.Reflection.Emit.Label emitTestNextImpOp;
+ System.Reflection.Emit.Label emitImpOpFound = il.DefineLabel ();
+ foreach (MethodInfo mi in destType.GetMethods (BindingFlags.Public | BindingFlags.Static)) {
+ if (mi.Name == "op_Implicit") {
+ if (mi.GetParameters () [0].ParameterType == destType)
+ continue;
+ emitTestNextImpOp = il.DefineLabel ();
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType);
+ il.Emit (OpCodes.Brfalse, emitTestNextImpOp);
+ if (mi.GetParameters () [0].ParameterType.IsValueType)
+ il.Emit (OpCodes.Unbox_Any, mi.GetParameters () [0].ParameterType);
+ else
+ il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType);
+
+ il.Emit (OpCodes.Call, mi);
+ il.Emit (OpCodes.Br, emitImpOpFound);
+
+ il.MarkLabel (emitTestNextImpOp);
+ }
+ }
+ //il.Emit (OpCodes.Br, emitImpOpNotFound);
+ il.MarkLabel (emitImpOpFound);
+ } else {//search both orig and dest types for implicit operators
+ MethodInfo miIO = getImplicitOp (origType, destType);
+ if (miIO != null)
+ il.Emit (OpCodes.Call, miIO);
+ }
+ }
+ }
+ }
+ internal static bool isValueType (object obj) => obj.GetType ().IsValueType;
+ /// <summary>
+ /// check type of current object on the stack and convert to dest type,
+ /// use loc_0 so store it as object!!!
+ /// </summary>
+ internal static void emitConvert(ILGenerator il, Type dstType){
+ System.Reflection.Emit.Label endConvert = il.DefineLabel ();
+ System.Reflection.Emit.Label convert = il.DefineLabel ();
+
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Brfalse, convert);
+
+ if (dstType.IsValueType)
+ il.Emit (OpCodes.Unbox_Any, dstType);
+ else
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Br, endConvert);
+
+ il.MarkLabel (convert);
+
+ if (dstType == typeof (string)) {
+ System.Reflection.Emit.Label emitNullStr = il.DefineLabel ();
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Brfalse, emitNullStr);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ il.Emit (OpCodes.Br, endConvert);
+ il.MarkLabel (emitNullStr);
+ il.Emit (OpCodes.Pop);//remove null string from stack
+ il.Emit (OpCodes.Ldstr, "");//replace with empty string
+ } else if (dstType.IsPrimitive) {
+ //il.Emit (OpCodes.Unbox_Any, dstType);
+ MethodInfo miconv = CompilerServices.GetConvertMethod (dstType);
+ if (miconv.IsStatic)
+ il.Emit (OpCodes.Call, miconv);
+ else
+ il.Emit (OpCodes.Callvirt, miconv);
+ }else if (dstType.IsValueType) {
+ System.Reflection.Emit.Label endConvert2 = il.DefineLabel ();
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Call, typeof (CompilerServices).GetMethod ("isValueType", BindingFlags.Static | BindingFlags.NonPublic));
+ System.Reflection.Emit.Label convertToValueType = il.DefineLabel ();
+ il.Emit (OpCodes.Brfalse, convertToValueType);
+
+ il.Emit (OpCodes.Unbox_Any, dstType);
+ il.Emit (OpCodes.Br, endConvert);
+
+ il.MarkLabel (convertToValueType);
+ //il.EmitWriteLine ($"convertToValueType:{dstType}");
+
+ //check if null
+ il.Emit (OpCodes.Dup);
+ LocalBuilder lbOrig = il.DeclareLocal (typeof (object));
+ LocalBuilder lbMI = il.DeclareLocal (typeof (MethodInfo));
+ il.Emit (OpCodes.Stloc, lbOrig);
+ il.Emit (OpCodes.Ldloc, lbOrig);
+
+ //il.Emit (OpCodes.Ldloc, lbOrig);
+ //il.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (object) }));
+ il.Emit (OpCodes.Brfalse, endConvert2);
+ //il.EmitWriteLine ($"search for implOp:{dstType}");
+ il.Emit (OpCodes.Ldloc, lbOrig);
+ il.Emit (OpCodes.Callvirt, miGetType);
+ il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ il.Emit (OpCodes.Call, miGetImplOp);
+ il.Emit (OpCodes.Stloc, lbMI);
+ il.Emit (OpCodes.Ldloc, lbMI);
+ convert = il.DefineLabel ();
+ il.Emit (OpCodes.Brtrue, convert);
+ //il.Emit (OpCodes.Ldloc, lbOrig);
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Br, endConvert2);
+
+ il.MarkLabel (convert);
+ //il.EmitWriteLine ($"implOp found, calling:{dstType}");
+ il.Emit (OpCodes.Pop);
+ il.Emit (OpCodes.Ldloc, lbMI);
+ il.Emit (OpCodes.Ldnull);//null instance for invoke
+ il.Emit (OpCodes.Ldc_I4_1);
+ il.Emit (OpCodes.Newarr, typeof (object));
+ il.Emit (OpCodes.Dup);//duplicate the array ref
+ il.Emit (OpCodes.Ldc_I4_0);//push the index 0
+ il.Emit (OpCodes.Ldloc, lbOrig);//push the orig value to convert
+ il.Emit (OpCodes.Stelem, typeof (object));//set the array element at index 0
+ il.Emit (OpCodes.Callvirt, miMIInvoke);
+ il.MarkLabel (endConvert2);
+ il.Emit (OpCodes.Unbox_Any, dstType);
+ } else{
+ LocalBuilder lbOrig = il.DeclareLocal (typeof (object));
+ il.Emit (OpCodes.Stloc, lbOrig); //save orig value in loc0
+ //first check if not null
+ il.Emit (OpCodes.Ldloc, lbOrig);
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Brfalse, endConvert);
+ il.Emit (OpCodes.Callvirt, miGetType);
+ il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ il.Emit (OpCodes.Call, miGetImplOp);
+ il.Emit (OpCodes.Dup);
+ convert = il.DefineLabel ();
+ il.Emit (OpCodes.Brtrue, convert);
+ il.Emit (OpCodes.Pop);
+ il.Emit (OpCodes.Ldloc, lbOrig);
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Br, endConvert);
+
+ il.MarkLabel (convert);
+ il.Emit (OpCodes.Ldnull);//null instance for invoke
+ il.Emit (OpCodes.Ldc_I4_1);
+ il.Emit(OpCodes.Newarr, typeof (object));
+ il.Emit (OpCodes.Dup);//duplicate the array ref
+ il.Emit (OpCodes.Ldc_I4_0);//push the index 0
+ il.Emit (OpCodes.Ldloc, lbOrig);//push the orig value to convert
+ il.Emit (OpCodes.Stelem, typeof (object));//set the array element at index 0
+ il.Emit (OpCodes.Callvirt, miMIInvoke);
+
+ //if (dstType.IsValueType)
+ // il.Emit (OpCodes.Unbox_Any, dstType);
+
+ }
+
+ il.MarkLabel (endConvert);
+ }
+
+ /// <summary>
+ /// Removes delegate from event handler by name
+ /// </summary>
+ static void removeEventHandlerByName(object instance, string eventName, string delegateName){
+ Type t = instance.GetType ();
+ FieldInfo fiEvt = getEventHandlerField (t, eventName);
+ if (fiEvt == null) {
+#if DEBUG_BINDING
+ Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance);
+#endif
+ return;
+ }
+ EventInfo eiEvt = t.GetEvent (eventName);
+ MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
+ if (multiDel != null) {
+ foreach (Delegate d in multiDel.GetInvocationList()) {
+ if (d.Method.Name == delegateName) {
+ eiEvt.RemoveEventHandler (instance, d);
+#if DEBUG_BINDING
+ Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+#endif
+ }
+ }
+ }
+ }
+ /// <summary>
+ /// Removes delegate from event handler by searching for the object they are bond to
+ /// </summary>
+ static void removeEventHandlerByTarget(object instance, string eventName, object target){
+ Type t = instance.GetType ();
+ FieldInfo fiEvt = getEventHandlerField (t, eventName);
+ EventInfo eiEvt = t.GetEvent (eventName);
+ MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
+ if (multiDel != null) {
+ foreach (Delegate d in multiDel.GetInvocationList()) {
+ if (d.Target == target) {
+ eiEvt.RemoveEventHandler (instance, d);
+#if DEBUG_BINDING
+ Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+#endif
+ }
+ }
+ }
+ }
+ /// <summary>
+ /// create delegate helper
+ /// </summary>
+ static Delegate createDel(object instance, Type eventType, string method){
+ Type t = instance.GetType ();
+ MethodInfo mi = t.GetMethod (method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (mi == null) {
+ Debug.WriteLine ("Handler Method '{0}' not found in '{1}'", method, t);
+ return null;
+ }
+ return Delegate.CreateDelegate (eventType, instance, mi);
+ }
+
+ internal static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){
+#if DEBUG_BINDING
+ Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression);
+#endif
+
+ Type lopType = null;
+
+ if (currentNode == null)
+ lopType = sourceEvent.DeclaringType;
+ else
+ lopType = currentNode.NodeType;
+
+#region Retrieve EventHandler parameter type
+ MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke");
+ ParameterInfo [] evtParams = evtInvoke.GetParameters ();
+ Type handlerArgsType = evtParams [1].ParameterType;
+#endregion
+
+ Type [] args = { typeof (object), handlerArgsType };
+ DynamicMethod dm = new DynamicMethod ("dyn_eventHandler",
+ typeof(void),
+ args, true);
+ ILGenerator il = dm.GetILGenerator (256);
+ il.Emit (OpCodes.Nop);
+
+ string [] srcLines = expression.Trim ().Split (new char [] { ';' });
+
+ foreach (string srcLine in srcLines) {
+ if (string.IsNullOrEmpty (srcLine))
+ continue;
+ string [] operandes = srcLine.Trim ().Split (new char [] { '=' });
+ if (operandes.Length != 2) //not an affectation
+ throw new NotSupportedException ();
+
+ System.Reflection.Emit.Label cancel = il.DefineLabel ();
+ System.Reflection.Emit.Label cancelFinalSet = il.DefineLabel ();
+ System.Reflection.Emit.Label success = il.DefineLabel ();
+
+ BindingMember lop = new BindingMember (operandes [0].Trim ());
+ BindingMember rop = new BindingMember (operandes [1].Trim ());
+
+ il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
+
+#region Left operande
+ PropertyInfo lopPI = null;
+
+ //in dyn handler, no datasource binding, so single name in expression are also handled as current node property
+ if (lop.IsSingleName)
+ lopPI = lopType.GetProperty (lop.Tokens [0]);
+ else if (lop.IsCurrentNodeProperty)
+ lopPI = lopType.GetProperty (lop.Tokens [1]);
+ else
+ lop.emitGetTarget (il, cancel);
+#endregion
+
+#region RIGHT OPERANDES
+ if (rop.IsStringConstant){
+ il.Emit (OpCodes.Ldstr, rop.Tokens[0]);
+ lop.emitSetProperty (il);
+ }else if (rop.IsSingleName && rop.Tokens[0] == "this"){
+ il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
+ lop.emitSetProperty (il);
+ }else if (rop.LevelsUp ==0 && !string.IsNullOrEmpty(rop.Tokens[0])) {//parsable constant depending on lop type
+ //if left operand is member of current node, it's easy to fetch type, else we should use reflexion in msil
+ if (lopPI == null){//accept GraphicObj members, but it's restricive
+ //TODO: we should get the parse method by reflexion, or something else
+ lopPI = typeof(Widget).GetProperty (lop.Tokens [lop.Tokens.Length-1]);
+ if (lopPI == null)
+ throw new NotSupportedException ();
+ }
+
+ MethodInfo lopParseMi = CompilerServices.miParseEnum;
+ if (lopPI.PropertyType.IsEnum){
+ //load type of enum
+ il.Emit(OpCodes.Ldtoken, lopPI.PropertyType);
+ il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ //load enum value name
+ il.Emit (OpCodes.Ldstr, operandes [1].Trim ());
+ //load false
+ il.Emit (OpCodes.Ldc_I4_0);
+ }else{
+ lopParseMi = lopPI.PropertyType.GetMethod ("Parse");
+ if (lopParseMi == null)
+ throw new Exception (string.Format
+ ("IML: no static 'Parse' method found in: {0}", lopPI.PropertyType.Name));
+
+ il.Emit (OpCodes.Ldstr, operandes [1].Trim ());
+ }
+ if (lopParseMi.IsStatic)
+ il.Emit (OpCodes.Call, lopParseMi);
+ else
+ il.Emit(OpCodes.Callvirt, lopParseMi);
+ //il.Emit (OpCodes.Unbox_Any, lopPI.PropertyType);
+ //emit left operand assignment
+ il.Emit (OpCodes.Callvirt, lopPI.GetSetMethod());
+ } else {//tree parsing and propert gets
+ il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
+
+ rop.emitGetTarget (il, cancelFinalSet);
+ rop.emitGetProperty (il, cancelFinalSet);
+ lop.emitSetProperty (il);
+ }
+#endregion
+
+ il.Emit (OpCodes.Br, success);
+
+ il.MarkLabel (cancelFinalSet);
+ il.Emit (OpCodes.Pop); //pop null MemberInfo on the stack causing cancelation
+ il.MarkLabel (cancel);
+ il.Emit (OpCodes.Pop); //pop null instance on the stack causing cancelation
+ il.MarkLabel (success);
+ }
+
+ il.Emit (OpCodes.Ret);
+
+ return dm.CreateDelegate (sourceEvent.EventHandlerType);
+ }
+
+ /// <summary>
+ /// MSIL helper, go n levels up
+ /// </summary>
+ /// <returns><c>true</c>, if logical parents are not null</returns>
+ /// <param name="instance">Start Instance</param>
+ /// <param name="levelCount">Levels to go upward</param>
+ internal static ILayoutable goUpNbLevels(ILayoutable instance, int levelCount){
+ ILayoutable tmp = instance;
+ int i = 0;
+ while (tmp != null && i < levelCount) {
+ tmp = tmp.LogicalParent;
+ i++;
+ }
+ return tmp;
+ }
+ /// <summary>
+ /// Splits expression on semicolon but ignore those between accolades
+ /// </summary>
+ internal static string[] splitOnSemiColumnOutsideAccolades (string expression){
+ List<String> exps = new List<string>();
+ int accCount = 0;
+ int expPtr = 0;
+ for (int c = 0; c < expression.Length; c++) {
+ switch (expression[c]){
+ case '{':
+ accCount++;
+ break;
+ case '}':
+ accCount--;
+ break;
+ case ';':
+ if (accCount > 0)
+ break;
+ exps.Add(expression.Substring(expPtr, c - expPtr - 1));
+ expPtr = c + 1;
+ break;
+ }
+ }
+ if (exps.Count == 0)
+ exps.Add(expression);
+ return exps.ToArray ();
+ }
+ /// <summary>
+ /// Try to get the type named strDataType, search first in crow assembly then in
+ /// entry assembly.
+ /// </summary>
+ /// <returns>the corresponding type object if found</returns>
+ /// <param name="strDataType">type name</param>
+ internal static Type getTypeFromName (string strDataType){
+ if (knownTypes.ContainsKey (strDataType))
+ return knownTypes [strDataType];
+ Type dataType = Type.GetType(strDataType);
+ if (dataType != null) {
+ knownTypes.Add (strDataType, dataType);
+ return dataType;
+ }
+ foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ()) {
+ if (a.IsDynamic)
+ continue;
+ foreach (Type expT in a.GetExportedTypes ()) {
+ if (expT.Name != strDataType && expT.FullName != strDataType)
+ continue;
+ if (!knownTypes.ContainsKey(strDataType))
+ knownTypes.Add (strDataType, expT);
+ return expT;
+ }
+ }
+ knownTypes.Add (strDataType, null);
+ return null;
+ }
+
+ //get value from member of object
+ internal static object getDataTypeAndFetch (object data, string fetchMethod){
+ Type dataType = data.GetType();
+ //Console.WriteLine ($"get data type and fetch {data}.{fetchMethod}");
+ MethodInfo miGetDatas = dataType.GetMethod (fetchMethod, new Type[] {});
+ if (miGetDatas == null)
+ miGetDatas = CompilerServices.SearchExtMethod (dataType, fetchMethod);
+
+ if (miGetDatas == null) {//in last resort, search among properties
+ PropertyInfo piDatas = dataType.GetProperty (fetchMethod);
+ if (piDatas == null) {
+ FieldInfo fiDatas = dataType.GetField (fetchMethod);
+ if (fiDatas == null)//and among fields
+ throw new Exception ("Fetch data member not found in ItemTemplate: " + fetchMethod);
+ return fiDatas.GetValue (data);
+ }
+ miGetDatas = piDatas.GetGetMethod ();
+ if (miGetDatas == null)
+ throw new Exception ("Read only property for fetching data in ItemTemplate: " + fetchMethod);
+ }
+ return miGetDatas.IsStatic ?
+ miGetDatas.Invoke (null, new object [] { data }) : miGetDatas.Invoke (data, null);
+ }
+ //TODO:memberinfo found here must be cached
+ internal static object getValue (Type dataType, object data, string member)
+ {
+ //Console.WriteLine ($"get value: {dataType} ; {data} ; {member}");
+
+ MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
+ if (miGetDatas != null)
+ return miGetDatas.Invoke (data, null);
+ MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
+ if (mbi == null) {
+ MethodInfo miExt = CompilerServices.SearchExtMethod (dataType, member);
+ if (miExt == null)//and among fields
+ throw new Exception ($"member {member} not found in {dataType}");
+ return miExt.Invoke (null, new object [] { data });
+ }
+ if (mbi.MemberType == MemberTypes.Property) {
+ miGetDatas = (mbi as PropertyInfo)?.GetGetMethod ();
+ if (miGetDatas == null)
+ throw new Exception ($"no getter found for property {member} in {dataType}");
+ return miGetDatas.Invoke (data, null);
+ }
+
+ FieldInfo fi = mbi as FieldInfo;
+ if (fi == null)
+ throw new Exception ($"member {member} not found in {dataType}");
+
+ return fi.GetValue (data);
+ }
+ internal static MemberInfo GetMemberInfo (Type dataType, string member, out Type returnType)
+ {
+ MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
+ if (miGetDatas != null) {
+ returnType = miGetDatas.ReturnType;
+ return miGetDatas;
+ }
+
+ MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
+ if (mbi == null)
+ miGetDatas = CompilerServices.SearchExtMethod (dataType, member);
+ else {
+ if (mbi is FieldInfo) {
+ FieldInfo fi = mbi as FieldInfo;
+ returnType = fi.FieldType;
+ return mbi;
+ }
+ if (mbi.MemberType == MemberTypes.Property)
+ miGetDatas = (mbi as PropertyInfo).GetGetMethod ();
+ else
+ miGetDatas = mbi as MethodInfo;
+ }
+ returnType = miGetDatas?.ReturnType;
+ return miGetDatas;
+
+ }
+ internal static void emitGetMemberValue (ILGenerator il, Type dataType, MemberInfo mi)
+ {
+ switch (mi.MemberType) {
+ case MemberTypes.Method:
+ MethodInfo mim = mi as MethodInfo;
+ if (mim.IsStatic)
+ il.Emit (OpCodes.Call, mim);
+ else
+ il.Emit (OpCodes.Callvirt, mim);
+ break;
+ case MemberTypes.Field:
+ il.Emit (OpCodes.Ldfld, mi as FieldInfo);
+ break;
+ }
+ }
+ //object is already on the stack
+ internal static void emitGetMemberValue (ILGenerator il, Type dataType, string member)
+ {
+ MethodInfo miGetDatas = dataType.GetMethod (member, new Type [] { });
+ if (miGetDatas != null) {
+ il.Emit (OpCodes.Callvirt, miGetDatas);
+ return;
+ }
+ MemberInfo mbi = dataType.GetMember (member).FirstOrDefault ();
+ if (mbi == null) {
+ MethodInfo miExt = CompilerServices.SearchExtMethod (dataType, member);
+ if (miExt == null)//and among fields
+ throw new Exception ($"member {member} not found in {dataType}");
+ il.Emit (OpCodes.Call, miExt);
+ return;
+ }
+ if (mbi.MemberType == MemberTypes.Property) {
+ miGetDatas = (mbi as PropertyInfo)?.GetGetMethod ();
+ if (miGetDatas == null)
+ throw new Exception ($"no getter found for property {member} in {dataType}");
+ il.Emit (OpCodes.Callvirt, miGetDatas);
+ return;
+ }
+
+ FieldInfo fi = mbi as FieldInfo;
+ if (fi == null)
+ throw new Exception ($"member {member} not found in {dataType}");
+
+ il.Emit (OpCodes.Ldfld, fi);
+ }
+
+ //helper to get member info underlying type.
+ internal static Type GetMemberInfoType (MemberInfo mi) =>
+ mi.MemberType == MemberTypes.Field ? (mi as FieldInfo).FieldType :
+ mi.MemberType == MemberTypes.Property ? (mi as PropertyInfo).PropertyType :
+ mi.MemberType == MemberTypes.Method ? (mi as MethodInfo).ReturnType : null;
+ }
+}
+
/// </summary>
Delegate templateBinding;
+#if DESIGN_MODE
+ public List<DynamicMethod> DsValueChangedDynMeths =>dsValueChangedDynMeths;
+ public List<Delegate> CachedDelegates => cachedDelegates;
+ /// <summary>
+ /// store indices of template delegate to be handled by root parentChanged event
+ /// </summary>
+ public List<int> TemplateCachedDelegateIndices => templateCachedDelegateIndices;
+ /// <summary>
+ /// Store template bindings in the instantiator
+ /// </summary>
+ public Delegate TemplateBinding => templateBinding;
+
+#endif
#region IML parsing
/// <summary>
/// Parses IML and build a dynamic method that will be used to instantiate one or multiple occurences of the IML file or fragment
ctx.SetDataSourceTypeForCurrentNode(CompilerServices.getTypeFromName (dataSourceType));
}
ctx.il.Emit (OpCodes.Ldloc_0);
- ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadDefaultVals);
+ ctx.il.Emit (OpCodes.Call, CompilerServices.miLoadDefaultVals);
#endregion
}
void emitTemplateBindings(IMLContext ctx, Dictionary<string, List<MemberAddress>> bindings){
//value changed dyn method
- DynamicMethod dm = new DynamicMethod ("dyn_tmpValueChanged",
+ DynamicMethod dm = new DynamicMethod ("dyn_tmpValueChanged" + NewId,
typeof (void), CompilerServices.argsValueChange, true);
ILGenerator il = dm.GetILGenerator (256);
//create parentchanged dyn meth in parallel to have only one loop over bindings
- DynamicMethod dmPC = new DynamicMethod ("dyn_InitAndLogicalParentChanged",
+ DynamicMethod dmPC = new DynamicMethod ("dyn_InitAndLogicalParentChanged" + NewId,
typeof (void),
CompilerServices.argsBoundDSChange, true);
ILGenerator ilPC = dmPC.GetILGenerator (256);
//store dschange delegate in instatiator instance for access while instancing graphic object
int delDSIndex = cachedDelegates.Count;
+
+ //Int32 fiLength = (Int32)il.GetType ().GetField ("code_len", BindingFlags.Instance | BindingFlags.NonPublic).GetValue (il);
+ //byte [] bytes = (byte[])il.GetType ().GetField ("code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue (il);
+
cachedDelegates.Add (dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
#endregion
#endregion
}
-#region emit dataSourceChanged event handler
+ #region emit dataSourceChanged event handler
//now we create the datasource changed method that will init the destination member with
//the actual value of the origin member of the datasource and then will bind the value changed
//dyn methode.
EventHandler<ValueChangeEventArgs> tmp = (EventHandler<ValueChangeEventArgs>)dm.CreateDelegate (typeof (EventHandler<ValueChangeEventArgs>), dest);
orig.ValueChanged += tmp;
}
-#endregion
+ #endregion
/// <summary>
/// search for graphic object type in crow assembly, if not found,
/// <param name="path">path of the iml file to load</param>
public virtual Widget CreateInstance (string path)
{
- try {
+ //try {
return GetInstantiator (path).CreateInstance ();
- } catch (Exception ex) {
- throw new Exception ("Error loading <" + path + ">:", ex);
- }
+ //} catch (Exception ex) {
+ // throw new Exception ("Error loading <" + path + ">:", ex);
+ //}
}
/// <summary>
/// Create an instance of a GraphicObject linked to this interface but not added to the GraphicTree
/// <param name="path">path of the iml file to load</param>
public virtual Widget CreateTemplateInstance (string path, Type declaringType)
{
- try {
+// try {
if (!Templates.ContainsKey (path))
Templates [path] = new Instantiator (this, GetTemplateStreamFromPath(path, declaringType), path);
return Templates [path].CreateInstance ();
- } catch (Exception ex) {
- throw new Exception ("Error loading Template <" + path + ">:", ex);
- }
+ //} catch (Exception ex) {
+ // throw new Exception ("Error loading Template <" + path + ">:", ex);
+ //}
}
/// <summary>
/// Fetch instantiator from cache or create it.
-//
-// Measure.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
+++ /dev/null
-//
-// Picture.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.IO;
-using Crow.Cairo;
-using System.Collections.Generic;
-
-namespace Crow
-{
- /// <summary>
- /// store data and dimensions for resource sharing
- /// </summary>
- internal class sharedPicture {
- //TODO: restructure this whith clever conceptual classes
- public object Data;
- public Size Dims;
- public sharedPicture (object _data, Size _dims){
- Data = _data;
- Dims = _dims;
- }
- }
- /// <summary>
- /// virtual class for loading and drawing picture in the interface
- ///
- /// Every loaded resources are stored in a dictonary with their path as key and shared
- /// among interface elements
- /// </summary>
- public abstract class Picture : Fill
- {
- /// <summary>
- /// share a single store for picture resources among usage in different controls
- /// </summary>
- internal static Dictionary<string, sharedPicture> sharedResources = new Dictionary<string, sharedPicture>();
-
- /// <summary>
- /// path of the picture
- /// </summary>
- public string Path;
- /// <summary>
- /// unscaled dimensions fetched on loading
- /// </summary>
- public Size Dimensions;
- /// <summary>
- /// if true and image has to be scalled, it will be scaled in both direction
- /// equaly
- /// </summary>
- public bool KeepProportions = false;
- /// <summary>
- /// allow or not the picture to be scalled on request by the painter
- /// </summary>
- public bool Scaled = true;
-
- #region CTOR
- /// <summary>
- /// Initializes a new instance of Picture.
- /// </summary>
- public Picture ()
- {
- }
- /// <summary>
- /// Initializes a new instance of Picture by loading the image pointed by the path argument
- /// </summary>
- /// <param name="path">image path, may be embedded</param>
- public Picture (string path)
- {
- Path = path;
- }
- #endregion
-
- #region Image Loading
- /// <summary>
- /// load the image for rendering from the stream given as argument
- /// </summary>
- /// <param name="stream">picture stream</param>
- //public abstract void Load(Interface iface, string path);
- #endregion
-
- /// <summary>
- /// abstract method to paint the image in the rectangle given in arguments according
- /// to the Scale and keepProportion parameters.
- /// </summary>
- /// <param name="gr">drawing Backend context</param>
- /// <param name="rect">bounds of the target surface to paint</param>
- /// <param name="subPart">used for svg only</param>
- public abstract void Paint(Context ctx, Rectangle rect, string subPart = "");
-
- #region Operators
- public static implicit operator Picture(string path)
- {
- if (string.IsNullOrEmpty (path))
- return null;
-
- Picture _pic = null;
-
- if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
- _pic = new SvgPicture (path);
- else
- _pic = new BmpPicture (path);
-
- return _pic;
- }
- public static implicit operator string(Picture _pic)
- {
- return _pic == null ? null : _pic.Path;
- }
- #endregion
-
- public static new object Parse(string path)
- {
- if (string.IsNullOrEmpty (path))
- return null;
-
- Picture _pic = null;
-
- if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
- _pic = new SvgPicture (path);
- else
- _pic = new BmpPicture (path);
-
- return _pic;
- }
- public override string ToString ()
- {
- return Path;
- }
- }
-}
-
public static bool operator <= (Point p1, Point p2) => p1.X <= p2.X && p1.Y <= p2.Y;
public static bool operator <= (Point s, int i) => s.X <= i && s.Y <= i;
- public override string ToString () => string.Format ("({0},{1})", X, Y);
+ public override string ToString () => string.Format ("{0},{1}", X, Y);
public override bool Equals (object obj) => obj is Point ? this == (Point)obj :
obj is Point && (Point)this == (Point)obj;
public static Point Parse (string s)
public static bool operator <= (PointD p1, PointD p2) => p1.X <= p2.X && p1.Y <= p2.Y;
public static bool operator <= (PointD s, double i) => s.X <= i && s.Y <= i;
- public override string ToString () => string.Format ("({0},{1})", X, Y);
+ public override string ToString () => string.Format ("{0},{1}", X, Y);
public override bool Equals (object obj) => obj is PointD ? this == (PointD)obj :
obj is Point && (Point)this == (Point)obj;
public static PointD Parse (string s)
+++ /dev/null
-//
-// SolidColor.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Xml.Serialization;
-using System.Reflection;
-using System.Diagnostics;
-using Crow.Cairo;
-
-
-
-namespace Crow
-{
- public class SolidColor : Fill
- {
- public Color color = Color.Transparent;
- #region CTOR
- public SolidColor(Color c)
- {
- color = c;
- }
- #endregion
-
- #region implemented abstract members of Fill
-
- public override void SetAsSource (Context ctx, Rectangle bounds = default(Rectangle))
- {
- ctx.SetSourceRGBA (color.R, color.G, color.B, color.A);
- }
- public static new object Parse(string s)
- {
- return new SolidColor((Color)s);
- }
- #endregion
-
- #region Operators
- public static implicit operator Color(SolidColor c)
- {
- return c.color;
- }
- public static implicit operator SolidColor(Color c)
- {
- return new SolidColor (c);
- }
- public static bool operator ==(SolidColor left, SolidColor right)
- {
- return left is SolidColor ? right is SolidColor ? true : false :
- left.color == right.color ? true : false;
- }
- public static bool operator !=(SolidColor left, SolidColor right)
- {
- return left is SolidColor ? right is SolidColor ? false : true :
- left.color == right.color ? false : true;
-
- }
- public override int GetHashCode ()
- {
- return color.GetHashCode();
- }
- public override bool Equals (object obj)
- {
- if (obj is Crow.Color)
- return color == (Color)obj;
- if (obj is SolidColor)
- return color == (obj as SolidColor).color;
- return false;
- }
-// public static bool operator ==(SolidColor c, string n)
-// {
-// return c.color.Name == n ? true : false;
-// }
-// public static bool operator !=(SolidColor c, string n)
-// {
-// return c.color.Name == n ? false : true;
-// }
-// public static bool operator ==(string n, SolidColor c)
-// {
-// return c.color.Name == n ? true : false;
-// }
-// public static bool operator !=(string n, SolidColor c)
-// {
-// return c.color.Name == n ? false : true;
-// }
- public static SolidColor operator *(SolidColor c, Double f)
- {
- return new SolidColor(new Color(c.color.R,c.color.G,c.color.B,c.color.A * f));
- }
- public static SolidColor operator +(SolidColor c1, SolidColor c2)
- {
- return new SolidColor(new Color(c1.color.R + c2.color.R,c1.color.G + c2.color.G,c1.color.B + c2.color.B,c1.color.A + c2.color.A));
- }
- public static SolidColor operator -(SolidColor c1, SolidColor c2)
- {
- return new SolidColor(new Color(c1.color.R - c2.color.R,c1.color.G - c2.color.G,c1.color.B - c2.color.B,c1.color.A - c2.color.A));
- }
- #endregion
-
- public override string ToString()
- {
- return color.ToString ();
- }
- }
-}
+++ /dev/null
-//
-// SvgPicture.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.IO;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// Derived from FILL for loading and drawing SVG images in the interface
- /// </summary>
- public class SvgPicture : Picture
- {
- Rsvg.Handle hSVG;
-
- #region CTOR
- /// <summary>
- /// Initializes a new instance of SvgPicture.
- /// </summary>
- public SvgPicture ()
- {}
- /// <summary>
- /// Initializes a new instance of SvgPicture by loading the SVG file pointed by the path argument
- /// </summary>
- /// <param name="path">image path, may be embedded</param>
- public SvgPicture (string path) : base(path)
- {
- Load ();
- }
- #endregion
-
- void Load ()
- {
- if (sharedResources.ContainsKey (Path)) {
- sharedPicture sp = sharedResources [Path];
- hSVG = (Rsvg.Handle)sp.Data;
- Dimensions = sp.Dims;
- return;
- }
- using (Stream stream = Interface.StaticGetStreamFromPath (Path)) {
- using (MemoryStream ms = new MemoryStream ()) {
- stream.CopyTo (ms);
-
- hSVG = new Rsvg.Handle (ms.ToArray ());
- Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height);
- }
- }
- sharedResources [Path] = new sharedPicture (hSVG, Dimensions);
- }
-
- public void LoadSvgFragment (string fragment) {
- hSVG = new Rsvg.Handle (System.Text.Encoding.Unicode.GetBytes(fragment));
- Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height);
- }
-
- #region implemented abstract members of Fill
-
- public override void SetAsSource (Context ctx, Rectangle bounds = default(Rectangle))
- {
- float widthRatio = 1f;
- float heightRatio = 1f;
-
- if (Scaled){
- widthRatio = (float)bounds.Width / Dimensions.Width;
- heightRatio = (float)bounds.Height / Dimensions.Height;
- }
-
- if (KeepProportions) {
- if (widthRatio < heightRatio)
- heightRatio = widthRatio;
- else
- widthRatio = heightRatio;
- }
-
- using (ImageSurface tmp = new ImageSurface (Format.Argb32, bounds.Width, bounds.Height)) {
- using (Context gr = new Context (tmp)) {
- gr.Translate (bounds.Left, bounds.Top);
- gr.Scale (widthRatio, heightRatio);
- gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
-
- hSVG.RenderCairo (gr);
- }
- ctx.SetSource (tmp);
- }
- }
- #endregion
-
- /// <summary>
- /// paint the image in the rectangle given in arguments according
- /// to the Scale and keepProportion parameters.
- /// </summary>
- /// <param name="gr">drawing Backend context</param>
- /// <param name="rect">bounds of the target surface to paint</param>
- /// <param name="subPart">limit rendering to svg part named 'subPart'</param>
- public override void Paint (Context gr, Rectangle rect, string subPart = "")
- {
- if (hSVG == null)
- return;
- float widthRatio = 1f;
- float heightRatio = 1f;
-
- if (Scaled) {
- widthRatio = (float)rect.Width / Dimensions.Width;
- heightRatio = (float)rect.Height / Dimensions.Height;
- }
- if (KeepProportions) {
- if (widthRatio < heightRatio)
- heightRatio = widthRatio;
- else
- widthRatio = heightRatio;
- }
-
- gr.Save ();
-
- gr.Translate (rect.Left,rect.Top);
- gr.Scale (widthRatio, heightRatio);
- gr.Translate (((float)rect.Width/widthRatio - Dimensions.Width)/2f, ((float)rect.Height/heightRatio - Dimensions.Height)/2f);
-
- if (string.IsNullOrEmpty (subPart))
- hSVG.RenderCairo (gr);
- else
- hSVG.RenderCairoSub (gr, "#" + subPart);
-
- gr.Restore ();
- }
- }
-}
-
Children.Remove(child);
child.Parent = null;
+ child.LogicalParent = null;
childrenRWLock.ExitWriteLock ();
/// Items loading thread
/// </summary>
void loading(){
- try {
+ //try {
loadPage (data, items, dataTest);
- } catch {
+ /*} catch (Exception ex) {
if (Monitor.IsEntered (IFace.LayoutMutex))
Monitor.Exit (IFace.LayoutMutex);
- Console.WriteLine ("loading thread aborted");
- }
+ Console.WriteLine ("loading thread aborted: " + ex.ToString());
+ }*/
}
// //if (!ItemTemplates.ContainsKey ("default"))
void cancelLoadingThread(){
if (loadingThread == null)
return;
-
bool updateMx = Monitor.IsEntered (IFace.UpdateMutex);
bool layoutMx = Monitor.IsEntered (IFace.LayoutMutex);
+#if DEBUG_LOG
+ DebugLog.AddEvent (DbgEvtType.TGCancelLoadingThread, this);
+#endif
+
if (layoutMx)
Monitor.Exit (IFace.LayoutMutex);
if (updateMx)
rootDataLevel = true;
#if DEBUG_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOLockLayouting, this);
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOLockUpdate, this);
#endif
lock (IFace.UpdateMutex) {
OnDataSourceChanged (this, dse);
il.Emit(OpCodes.Ret);
#endregion
- try {
+ //try {
IFace.DefaultValuesLoader[styleKey] = (Interface.LoaderInvoker)dm.CreateDelegate(typeof(Interface.LoaderInvoker));
IFace.DefaultValuesLoader[styleKey] (this);
- } catch (Exception ex) {
+ /*} catch (Exception ex) {
throw new Exception ("Error applying style <" + styleKey + ">:", ex);
- }
+ }*/
#if DEBUG_LOG
dbgEvt.end = DebugLog.chrono.ElapsedTicks;
#endif
if (Parent == null)
return;
+#if DEBUG_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent (DbgEvtType.GOLockLayouting, this);
+#endif
lock (IFace.LayoutMutex) {
//prevent queueing same LayoutingType for this
layoutType &= (~RegisteredLayoutings);
if (layoutType.HasFlag (LayoutingType.ArrangeChildren))
IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this));
}
+#if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+#endif
}
/// <summary> trigger dependant sizing component update </summary>
else if (Width == Measure.Stretched)
Slot.Width = Parent.ClientRectangle.Width;
else
- Slot.Width = (int)Math.Round ((double)(Parent.ClientRectangle.Width * Width) / 100.0);
+ Slot.Width = (int)Math.Round ((double)(Parent.ClientRectangle.Width * Width) / 100.0);
if (Slot.Width < 0)
return false;
long currentTick = 0, selStart = -1, selEnd = -1, minTicks = 0, maxTicks = 0, visibleTicks = 0;
int currentLine = -1;
- int visibleLines;
+ int visibleLines = 1;
public string LogFile {
get { return logFile; }
loadDebugFile ();
-
NotifyValueChanged ("LogFile", logFile);
RegisterForGraphicUpdate ();
}
leftMargin = 2.5 + maxNameWidth;
- fe = gr.FontExtents;
-
topMargin = 2.0 * fe.Height;
updateVisibleLines ();
}
void updateVisibleLines(){
- visibleLines = (int)Math.Floor (((double)ClientRectangle.Height - topMargin) / fe.Height);
+ visibleLines = fe.Height < 1 ? 1 : (int)Math.Floor (((double)ClientRectangle.Height - topMargin) / fe.Height);
NotifyValueChanged ("VisibleLines", visibleLines);
updateMaxScrollY ();
}
get { return base.Font; }
set {
base.Font = value;
+ using (Context gr = new Context (IFace.surf)) {
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+
+ fe = gr.FontExtents;
+ }
loadDebugFile ();
}
}
-
public override int ScrollY {
get {
return base.ScrollY;
Color c = Color.Black;
- if (evt.type == DbgEvtType.GOProcessLayouting) {
+ if (evt.type == DbgEvtType.GOProcessLayouting) {
switch (evt.data.result) {
case LayoutingQueueItem.Result.Success:
c = Crow.Color.Green;
c = Crow.Color.Orange;
break;
}
- } else if (colors.ContainsKey (evt.type))
+ } else if (evt.type.HasFlag (DbgEvtType.GOLock))
+ c = Color.BlueViolet;
+ else if (colors.ContainsKey (evt.type))
c = colors [evt.type];
- else
- System.Diagnostics.Debugger.Break ();
-
+ //else
+ // System.Diagnostics.Debugger.Break ();
+ c = c.AdjustAlpha (0.2);
gr.SetSourceColor (c);
gr.Rectangle (x, penY, w, fe.Height);
IFaceEndDrawing = 0x0106,
IFaceUpdate = 0x0107,
//10 nth bit set for graphic obj
- GraphicObject = 0x0200,
- GOClassCreation = 0x0201,
- GOInitialization = 0x0202,
- GOClippingRegistration = 0x0203,
- GORegisterClip = 0x0204,
- GORegisterForGraphicUpdate = 0x0205,
- GOEnqueueForRepaint = 0x0206,
- GOLayouting = 0x0400,
- GORegisterLayouting = 0x0607,
- GOProcessLayoutingWithNoParent = 0x0608,
- GOProcessLayouting = 0x0609,
- GODraw = 0x020a,
- GORecreateCache = 0x020b,
- GOUpdateCacheAndPaintOnCTX = 0x020c,
- GOPaint = 0x020d,
- GONewDataSource = 0x020e,
+ GraphicObject = 0x0100,
+ Warning = 0x4000,
+ Error = 0x8000,
+ GOClassCreation = GraphicObject | 0x01,
+ GOInitialization = GraphicObject | 0x02,
+ GOClippingRegistration = GraphicObject | 0x03,
+ GORegisterClip = GraphicObject | 0x04,
+ GORegisterForGraphicUpdate = GraphicObject | 0x05,
+ GOEnqueueForRepaint = GraphicObject | 0x06,
+ GONewDataSource = GraphicObject | 0x07,
+ GOLayouting = 0x0200,
+ Drawing = 0x0400,
GOLock = 0x0800,
- GOLockUpdate = 0x0a01,
- GOLockClipping = 0x0a02,
- GOLockRender = 0x0a03,
- GOLockLayouting = 0x0a04,
+ TemplatedGroup = 0x1000,
+ GORegisterLayouting = GraphicObject | GOLayouting | 0x01,
+ GOProcessLayouting = GraphicObject | GOLayouting | 0x02,
+ GOProcessLayoutingWithNoParent = Warning | GraphicObject | GOLayouting | 0x01,
+ GODraw = GraphicObject | Drawing | 0x01,
+ GORecreateCache = GraphicObject | Drawing | 0x02,
+ GOUpdateCacheAndPaintOnCTX = GraphicObject | Drawing | 0x03,
+ GOPaint = GraphicObject | Drawing | 0x04,
+
+ GOLockUpdate = GraphicObject | GOLock | 0x01,
+ GOLockClipping = GraphicObject | GOLock | 0x02,
+ GOLockRender = GraphicObject | GOLock | 0x03,
+ GOLockLayouting = GraphicObject | GOLock | 0x04,
+
+ TGCancelLoadingThread = GraphicObject | TemplatedGroup | 0x01,
}
/// <summary>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DefineConstants>TRACE;DEBUG;NETFRAMEWORK;NET471</DefineConstants>
+ <DebugType>full</DebugType>
+ <DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
<Reference Include="System" />
<LogicalName>HelloWorld.%(Filename)%(Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="Mono.Cecil" Version="0.11.1" />
+ </ItemGroup>
</Project>
--- /dev/null
+// Copyright (c) 2020 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 Crow;
+
+namespace HelloWorld
+{
+ public class ILView : Widget
+ {
+ public ILView ()
+ {
+ }
+ }
+}
using System;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
using Crow;
+using Crow.IML;
namespace HelloWorld
{
vke.Run ();
}
}
+
protected override void Startup ()
{
CMDQuit = new Command (new Action (() => running = false)) { Caption = "Quit", Icon = new SvgPicture ("#Crow.Icons.exit-symbol.svg") };
w.DataSource = this;
}
+ public SolidColor testColor = Color.Red;
+ public SolidColor TestColor {
+ get => testColor;
+ set {
+ if (testColor == value)
+ return;
+ testColor = value;
+ NotifyValueChanged ("TestColor", testColor);
+ }
+ }
+
Color [] colors = { Color.Blue, Color.DarkGoldenRod, Color.Red, Color.Azure, Color.Brown, Color.Black, Color.White, Color.Pink };
int ptr = 0;
if (ptr == colors.Length)
ptr = 0;
}
+ public override bool OnKeyDown (Key key)
+ {
+ switch (key) {
+ case Key.d:
+ dump ();
+ break;
+ case Key.space:
+ TestColor = Color.Green;
+ break;
+ default:
+ return base.OnKeyDown (key);
+ }
+ return true;
+ }
+
+ void dump ()
+ {
+ Instantiator inst = Instantiators ["#HelloWorld.helloworld.crow"];
+
+ foreach (Delegate cd in inst.CachedDelegates) {
+ FieldInfo mb = typeof(Delegate).GetField("original_method_info", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
+
+ DynamicMethod dynMethod = mb.GetValue (cd) as DynamicMethod;
+ /*Console.WriteLine (typeof (ILGenerator).GetFields (BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField));
+
+ var ilgen = dynMethod.GetILGenerator ();
+
+
+
+*/
+
+ MethodBody body = dynMethod.GetMethodBody ();
+
+ byte [] il = body.GetILAsByteArray ();
+ foreach (byte b in il) {
+ Console.Write ($"{b:x2} ");
+ //Console.WriteLine (b);
+ }
+
+ }
+
+ }
}
}
<?xml version="1.0"?>
-
- <VerticalStack>
- <Label Text="Hello World" Font="mono, 20"/>
- <Image Path="#Crow.Icons.crow.svg"/>
- <CheckBox/>
- </VerticalStack>
-
-
+<VerticalStack>
+ <TextBox Text="{TestColor}"/>
+ <ColorPicker CurrentColor="{²TestColor}" />
+</VerticalStack>
+<!--<ScrollBar Orientation="Vertical" Height="Stretched" Width="10" />-->
\ No newline at end of file
-<?xml version="1.0"?>
-<Window Caption="Showcase" Height="90%" Width="90%">
- <HorizontalStack >
+<?xml version="1.0" encoding="UTF-8"?>
+<Window Caption="Showcase" Height="90%" Width="90%" Background="Jet">
+ <HorizontalStack>
<VerticalStack Width="30%" Margin="5">
<GroupBox Caption="Performance" Height="Fit">
- <VerticalStack DataSource="{drawingMeasure}" Width="90%" Height="Fit" Spacing="2" >
+ <VerticalStack DataSource="{drawingMeasure}" Width="90%" Height="Fit" Spacing="2">
<HorizontalStack Height="Fit" Tooltip="Frame per second">
- <Label Text="Fps:" Style="FpsLabel"/>
- <Label Text="{minimum}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Fps:" />
+ <Label Style="FpsDisp" Text="{minimum}" />
</HorizontalStack>
<HorizontalStack Height="Fit" Tooltip="Minimum Frame per second">
- <Label Text="Min:" Style="FpsLabel"/>
- <Label Text="{fpsMin}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Min:" />
+ <Label Style="FpsDisp" Text="{fpsMin}" />
</HorizontalStack>
<HorizontalStack Height="Fit" Tooltip="Maximum Frame per second">
- <Label Text="Max:" Style="FpsLabel"/>
- <Label Text="{fpsMax}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Max:" />
+ <Label Style="FpsDisp" Text="{fpsMax}" />
</HorizontalStack>
<HorizontalStack Height="Fit" Tooltip="Update loop duration">
- <Label Text="Update:" Style="FpsLabel"/>
- <Label Text="{update}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Update:" />
+ <Label Style="FpsDisp" Text="{update}" />
</HorizontalStack>
<HorizontalStack Height="Fit" Tooltip="Layouting process duration">
- <Label Text="Layouting:" Style="FpsLabel"/>
- <Label Text="{layouting}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Layouting:" />
+ <Label Style="FpsDisp" Text="{layouting}" />
</HorizontalStack>
<HorizontalStack Height="Fit" Tooltip="Clipping duration">
- <Label Text="Clipping:" Style="FpsLabel"/>
- <Label Text="{clipping}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Clipping:" />
+ <Label Style="FpsDisp" Text="{clipping}" />
</HorizontalStack>
<HorizontalStack Height="Fit">
- <Label Text="Drawing:" Style="FpsLabel"/>
- <Label Text="{drawing}" Style="FpsDisp"/>
+ <Label Style="FpsLabel" Text="Drawing:" />
+ <Label Style="FpsDisp" Text="{drawing}" />
</HorizontalStack>
</VerticalStack>
</GroupBox>
- <Label Width="Stretched" Margin="3" Background="DimGrey"/>
- <TextBox Text="TextBox" Multiline="true" Margin="3"/>
+ <Label Width="Stretched" Margin="3" Background="DimGrey" />
+ <TextBox Text="TextBox" Multiline="true" Margin="3" />
<HorizontalStack Height="Fit" Margin="5" Background="DimGrey" CornerRadius="10">
<VerticalStack Spacing="5" Width="50%">
- <CheckBox Fit="true" Caption="test"/>
- <CheckBox Fit="true"/>
- <CheckBox Fit="true"/>
- <CheckBox Fit="true" IsChecked="true"/>
+ <CheckBox Fit="true" Caption="test" />
+ <CheckBox Fit="true" />
+ <CheckBox Fit="true" />
+ <CheckBox Fit="true" IsChecked="true" />
</VerticalStack>
<VerticalStack Spacing="5" Width="50%">
- <RadioButton Fit="true"/>
- <RadioButton Fit="true" IsChecked="true"/>
- <RadioButton Fit="true"/>
- <RadioButton Fit="true"/>
+ <RadioButton Fit="true" />
+ <RadioButton Fit="true" IsChecked="true" />
+ <RadioButton Fit="true" />
+ <RadioButton Fit="true" />
</VerticalStack>
</HorizontalStack>
<HorizontalStack Height="Fit" Margin="5">
- <Label Text="MouseEvents" Width="50%" Margin="3" Focusable="true"
- Background="Jet"
- Foreground="DimGrey"
- TextAlignment="Center"
- MouseEnter="{Foreground=White}"
- MouseLeave="{Foreground=DimGrey}"
- MouseDown="{Background=DarkRed}"
- MouseClick="{Foreground=Green}"
- MouseDoubleClick="{Foreground=Yellow}"
- MouseUp="{Background=Jet}"/>
- <Label Text="MouseEvents" Width="50%" Margin="3"
- Background="Jet"
- Foreground="DimGrey"
- TextAlignment="Center"
- MouseClick="{Foreground=Green}"
- MouseDoubleClick="{Foreground=Yellow}"
- MouseEnter="{Foreground=White}"
- MouseLeave="{Foreground=DimGrey}"
- MouseDown="{Background=SeaGreen}"
- MouseUp="{Background=DimGrey}"/>
+ <Label Text="MouseEvents" Width="50%" Margin="3" Focusable="true" Background="Jet" Foreground="DimGrey" TextAlignment="Center" MouseEnter="{Foreground=White}" MouseLeave="{Foreground=DimGrey}" MouseDown="{Background=DarkRed}" MouseClick="{Foreground=Green}" MouseDoubleClick="{Foreground=Yellow}" MouseUp="{Background=Jet}" />
+ <Label Text="MouseEvents" Width="50%" Margin="3" Background="Jet" Foreground="DimGrey" TextAlignment="Center" MouseClick="{Foreground=Green}" MouseDoubleClick="{Foreground=Yellow}" MouseEnter="{Foreground=White}" MouseLeave="{Foreground=DimGrey}" MouseDown="{Background=SeaGreen}" MouseUp="{Background=DimGrey}" />
</HorizontalStack>
<GroupBox Caption="Templated controls" Height="Fit" Margin="5">
<HorizontalStack Height="Fit">
<VerticalStack Width="50%">
- <CheckBox IsChecked="true" Style="CheckBox2"/>
- <CheckBox Style="CheckBox2"/>
- <CheckBox Style="CheckBox2"/>
- <CheckBox Style="CheckBox2"/>
+ <CheckBox Style="CheckBox2" IsChecked="true" />
+ <CheckBox Style="CheckBox2" />
+ <CheckBox Style="CheckBox2" />
+ <CheckBox Style="CheckBox2" />
</VerticalStack>
- <Splitter/>
+ <Splitter />
<VerticalStack Width="50%">
- <RadioButton Style="RadioButton2"/>
- <RadioButton Style="RadioButton2"/>
- <RadioButton Style="RadioButton2"/>
- <RadioButton Style="RadioButton2"/>
+ <RadioButton Style="RadioButton2" />
+ <RadioButton Style="RadioButton2" />
+ <RadioButton Style="RadioButton2" />
+ <RadioButton Style="RadioButton2" />
</VerticalStack>
</HorizontalStack>
</GroupBox>
<HorizontalStack Height="Fit">
- <Label Text="Spinner"/>
- <Spinner Fit="true"/>
+ <Label Text="Spinner" />
+ <Spinner Fit="true" />
</HorizontalStack>
<HorizontalStack Height="Fit">
- <Button Caption="Button"/>
- <Button Caption="Button" IsEnabled="false"/>
+ <Button Caption="Button">
+ <Label Font="{./Font}" Name="caption" Margin="3" Foreground="LightGrey" Text="{./Caption}" />
+ </Button>
+ <Button Caption="Button" IsEnabled="false">
+ <Label Font="{./Font}" Name="caption" Margin="3" Foreground="LightGrey" Text="{./Caption}" />
+ </Button>
</HorizontalStack>
</VerticalStack>
- <Splitter/>
+ <Splitter />
<VerticalStack Width="40%" Margin="5" Spacing="5">
<Expandable>
- <Image Path="#Crow.Icons.crow.svg"/>
+ <Image Path="#Crow.Icons.crow.svg" />
</Expandable>
- <Popper>
- <Border Fit="True" Background="DimGrey" CornerRadius="0" BorderWidth="1">
- <Image Path="#Crow.Icons.crow.svg" Width="100" Height="100" Margin="10"
- MouseEnter="{Background=LightGrey}"
- MouseLeave="{Background=Transparent}"/>
- </Border>
- </Popper>
- <Slider Height="10" Width="90%"/>
+ <Popper />
+ <Slider Height="10" Width="90%" />
<Container Height="Fit" Width="200" Background="DimGrey" Margin="2" CornerRadius="5">
- <ProgressBar Background="DimGrey" Height="10" Value="50"/>
+ <ProgressBar Background="DimGrey" Height="10" Value="50" />
</Container>
<Image Path="#Crow.Icons.crow.svg" Width="60" Height="60" Background="LightGrey" />
-<!-- <TabView Name="tabview1"
- Height="120" Orientation="Horizontal" Spacing="15">
- <TabItem Name="TabItem1" Caption="Tab 1" Margin="0">
- <VerticalStack Fit="true">
- <CheckBox/>
- <CheckBox/>
- <CheckBox/>
- <CheckBox/>
- </VerticalStack>
- </TabItem>
- <TabItem Name="TabItem2" Caption="Tab 2" Background="Grey">
- <VerticalStack Fit="true">
- <RadioButton/>
- <RadioButton/>
- <RadioButton/>
- <RadioButton/>
- </VerticalStack>
- </TabItem>
- <TabItem Name="TabItem3" Caption="Tab 3" Background="Grey">
- <Container Margin="5" CornerRadius="2">
- <TextBox Height="Stretched" Margin="5" Multiline="true" TextAlignment="TopLeft"/>
- </Container>
- </TabItem>
- </TabView>-->
- <MessageBox Movable="false"/>
+ <MessageBox Movable="false" />
<ColorPicker CurrentColor="{²../go.Background}" Name="colorPicker" Margin="5" />
- <Widget Name="go" Width="100" Height="60" Background="{../../colorList.SelectedItem}"/>
- <Label Text="{../colorPicker.CurrentColor}"/>
+ <Widget Name="go" Width="100" Height="60" Background="{../../colorList.SelectedItem}" />
+ <Label Text="{../colorPicker.CurrentColor}" />
</VerticalStack>
- <Splitter/>
+ <Splitter />
<VerticalStack Width="30%" Margin="5">
-<!-- <Border Margin="5" Height="Fit">
- <Label Width="Stretched" Margin="1" Text="{../../dv.SelectedItem}"/>
- </Border>
- <Border Margin="5" Height="30%">
- <DirectoryView Name="dv" CurrentDirectory="/" Margin="1"/>
- </Border>
- <Splitter/>-->
- <ListBox Name="colorList" Data="{TestList}" Margin="5"
- ItemTemplate="Interfaces/colorItem.crow"
- Template="#Crow.ScrollingListBox.template"
- />
+ <ListBox Name="colorList" Data="{TestList}" Margin="5" ItemTemplate="Interfaces/colorItem.crow" />
</VerticalStack>
</HorizontalStack>
</Window>
\ No newline at end of file