]> O.S.I.I.S - jp/crow.git/commitdiff
hosted command
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 15 Sep 2021 19:26:39 +0000 (19:26 +0000)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 15 Sep 2021 19:26:39 +0000 (19:26 +0000)
28 files changed:
Crow/Crow.csproj
Crow/src/Command/ActionCommand.cs
Crow/src/Command/Binding.cs [new file with mode: 0644]
Crow/src/Command/Command.cs
Crow/src/Command/CommandGroup.cs
Crow/src/Command/KeyBinding.cs [new file with mode: 0644]
Crow/src/Command/ToggleCommand.cs
Crow/src/DebugUtils/PerformanceMeasure.cs
Crow/src/Enums.cs
Crow/src/EventArgs/ListChangedEventArg.cs
Crow/src/Fill/Gradient.cs
Crow/src/IML/CompilerServices.cs
Crow/src/Input/KeyEventArgs.cs
Crow/src/Input/MouseEventArgs.cs
Crow/src/Interface.cs
Crow/src/Widgets/Button.cs
Crow/src/Widgets/Label.cs
Crow/src/Widgets/MenuItem.cs
Crow/src/Widgets/PrivateContainer.cs
Crow/src/Widgets/TextBox.cs
Crow/src/Widgets/Widget.cs
Samples/ShowCase/ShowCase.cs
Samples/ShowCase/ui/showcase.crow
Samples/common/src/Editor.cs
Samples/common/src/SampleBase.cs
Samples/common/src/SampleBaseForEditor.cs
Samples/common/ui/Interfaces/Experimental/hostedCommand.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/Experimental/toggleCmd.crow

index 3b054bb463e721149891ee148c7a4b866f06d12d..1c61b00e902b5e1c9ecb3b68b003be3d9fce6383 100644 (file)
@@ -3,10 +3,10 @@
        <PropertyGroup>
 <!--           <TargetFrameworks>netstandard2.0</TargetFrameworks>-->
                <TargetFramework>netstandard2.1</TargetFramework>
-               
+
                <AssemblyVersion>$(CrowVersion)</AssemblyVersion>
                <PackageVersion>$(CrowPackageVersion)</PackageVersion>
-               
+
                <Title>C# Rapid Open Widget Toolkit</Title>
                <Description>C.R.O.W. is a widget toolkit and rendering engine developed in C# with templates, styles, compositing, and bindings.</Description>
                <License>MIT</License>
@@ -23,7 +23,7 @@
                <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
                <GenerateDocumentationFile>true</GenerateDocumentationFile>
                <NoWarn>$(NoWarn);1591;1587;1570;1572;1573;1574</NoWarn>
-               <DefineConstants>MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS</DefineConstants>          
+               <DefineConstants>MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS</DefineConstants>
                <EnableDefaultItems>false</EnableDefaultItems>
                <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
                <!--<AllowUnsafeBlocks>true</AllowUnsafeBlocks>-->
@@ -40,7 +40,7 @@
        </ItemGroup>
        <ItemGroup>
                <!--<PackageReference Include="FastEnum" Version="1.5.3" />-->
-               <PackageReference Include="Enums.NET" Version="4.0.0" />                
+               <PackageReference Include="Enums.NET" Version="4.0.0" />
                <PackageReference Include="glfw-sharp" Version="$(GlfwSharpVersion)" />
        </ItemGroup>
 
index 02bec998bc36336908651c62dbfd739cf1009b3c..f484e0eda2a38f788e9c91fbf6dd0478561c97df 100644 (file)
@@ -39,9 +39,22 @@ namespace Crow {
                {
                        execute = executeAction;
                }
+               public ActionCommand (ICommandHost _host, string caption, Action executeAction, string icon = null, KeyBinding _keyBinding = null,
+                                               Binding<bool> _canExecuteBinding = null)
+                       : base (_host, caption, icon, _keyBinding, _canExecuteBinding)
+               {
+                       execute = executeAction;
+               }
+               public ActionCommand (ICommandHost _host, string caption, Action<object> executeAction, string icon = null, KeyBinding _keyBinding = null,
+                                               Binding<bool> _canExecuteBinding = null)
+                       : base (_host, caption, icon, _keyBinding, _canExecuteBinding)
+               {
+                       execute = executeAction;
+               }
+
                #endregion
 
-               Delegate execute;
+               protected Delegate execute;
 
                /// <summary>
                /// trigger the execution of the command
@@ -56,4 +69,14 @@ namespace Crow {
                        }
                }
        }
+       public class ActionCommand<T> : ActionCommand {
+               public ActionCommand (Action<T> _executeAction) {
+                       execute = _executeAction;
+               }
+               public ActionCommand (string caption, Action<T> executeAction, string icon = null, bool _canExecute = true)
+                       : base (caption, default(Action), icon, _canExecute)
+               {
+                       execute = executeAction;
+               }
+       }
 }
diff --git a/Crow/src/Command/Binding.cs b/Crow/src/Command/Binding.cs
new file mode 100644 (file)
index 0000000..4437e98
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (c) 2021-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Reflection;
+using System.Linq;
+using EnumsNET;
+using Glfw;
+using System.Reflection.Emit;
+
+namespace Crow
+{
+       public class Binding<T> {
+               public string SourceMember;
+               public Func<T> FetchFunc;
+
+               public Binding (string memberName, Func<T> fetchFunc = null) {
+                       SourceMember = memberName;
+                       FetchFunc = fetchFunc;
+               }
+               public T Get (object instance) {
+                       MemberInfo mbi = instance.GetType().GetMember (SourceMember, BindingFlags.Instance | BindingFlags.Public ).FirstOrDefault();
+                       if (mbi is PropertyInfo pi)
+                               return (T)pi.GetGetMethod ().Invoke (instance, null);
+                       else if (mbi is FieldInfo fi)
+                               return (T)fi.GetValue (instance);
+                       else if (mbi is MethodInfo mi)
+                               return (T)mi.Invoke (instance, null);
+                       else
+                               throw new Exception ($"unsupported member type for Binding<T>: {mbi.MemberType}");
+               }
+               public Func<T> CreateGetter (object instance) {
+                       MemberInfo mbi = instance.GetType().GetMember (SourceMember, BindingFlags.Instance | BindingFlags.Public).FirstOrDefault();
+                       if (mbi is PropertyInfo pi) {
+                               return (Func<T>)Delegate.CreateDelegate (typeof (Func<T>), instance, pi.GetGetMethod ());
+                       } else if (mbi is FieldInfo fi) {
+                               DynamicMethod dm = new DynamicMethod($"{fi.ReflectedType.FullName}_fldget", typeof(T), new Type[] { fi.ReflectedType }, false);
+                               ILGenerator il = dm.GetILGenerator ();
+                               il.Emit (OpCodes.Ldarg_0);
+                               il.Emit (OpCodes.Ldfld, fi);
+
+                               il.Emit(OpCodes.Ret);
+
+                               return (Func<T>)dm.CreateDelegate (typeof (Func<T>), instance);
+                       } else
+                               throw new Exception ("unsupported member type for Binding.CreateGetter");
+               }
+               public Action<T> CreateSetter (object instance) {
+                       MemberInfo mbi = instance.GetType().GetMember (SourceMember, BindingFlags.Instance | BindingFlags.Public).FirstOrDefault();
+                       if (mbi is PropertyInfo pi) {
+                               return (Action<T>)Delegate.CreateDelegate (typeof (Action<T>), instance, pi.GetSetMethod ());
+                       } else if (mbi is FieldInfo fi) {
+                               DynamicMethod dm = new DynamicMethod($"{fi.ReflectedType.FullName}_fldset", null, new Type[] { fi.ReflectedType, typeof(T)}, false);
+                               ILGenerator il = dm.GetILGenerator ();
+                               il.Emit (OpCodes.Ldarg_0);
+                               il.Emit (OpCodes.Ldarg_1);
+                               il.Emit (OpCodes.Stfld, fi);
+
+                               il.Emit(OpCodes.Ret);
+
+                               return (Action<T>)dm.CreateDelegate (typeof (Action<T>), instance);
+                       } else
+                               throw new Exception ("unsupported member type for Binding CreateSetter");
+               }
+       }
+}
\ No newline at end of file
index f44fe5b35803fc3b634b234fdd2e9a0713063ded..85c444137dbb0f4d6b476a20a44ca29504fde5e1 100644 (file)
@@ -7,20 +7,56 @@ using System.ComponentModel;
 using System.Threading.Tasks;
 
 namespace Crow {
+
+       public interface ICommandHost : IValueChange
+       {
+               event EventHandler<KeyEventArgs> KeyDown;
+       }
        /// <summary>
        /// Base abstract class for commands with an execute method.
        /// </summary>
-       public abstract class Command : CommandBase
+       public abstract class Command : CommandBase, IDisposable
        {
 
                #region CTOR
                public Command () {}
-               public Command (string caption, string icon = null, bool _canExecute = true)
+               public Command (string caption, string icon = null, bool _canExecute = true )
                        :base (caption, icon)
-               {}
+               {
+                       CanExecute = _canExecute;
+               }
+               public Command (ICommandHost _host, string caption, string icon, KeyBinding _keyBinding = null,
+                                               bool _canExecute = true)
+                       : this (_host, caption, icon, _keyBinding, null)
+               {
+                       CanExecute = _canExecute;
+               }
+
+               public Command (ICommandHost _host, string caption, string icon, KeyBinding _keyBinding = null,
+                                               Binding<bool> _canExecuteBinding = null)
+                       : base (caption, icon)
+               {
+                       host = _host;
+                       keyBinding = _keyBinding;
+                       canExecuteBinding = _canExecuteBinding;
+
+                       if (HasKeyBinding)
+                               host.KeyDown += key_handler;
+                       if (HasCanExecuteBinding) {
+                               host.ValueChanged += canExecuteBinding_handler;
+                               CanExecute = canExecuteBinding.Get (host);
+                       }
+               }
                #endregion
 
+               protected ICommandHost host;
                bool canExecute = true;
+               KeyBinding keyBinding;
+               Binding<bool> canExecuteBinding;
+
+               public KeyBinding KeyBinding => keyBinding;
+               public bool HasKeyBinding => keyBinding != null;
+               public bool HasCanExecuteBinding => canExecuteBinding != null;
 
                /// <summary>
                /// if true, command may be executed,
@@ -46,5 +82,34 @@ namespace Crow {
                        base.raiseAllValuesChanged();
                        NotifyValueChanged ("CanExecute", CanExecute);
                }
+               void key_handler (object sender, KeyEventArgs e) {
+                       if (CanExecute && e.Key == keyBinding.Key && e.Modifiers == keyBinding.Modifiers) {
+                               Execute (sender);
+                               e.Handled = true;
+                       }
+               }
+               void canExecuteBinding_handler (object sender, ValueChangeEventArgs e) {
+                       if (e.MemberName == canExecuteBinding.SourceMember)
+                               CanExecute = (bool)e.NewValue;
+               }
+               #region IDispose implementation
+               protected bool disposed;
+               protected virtual void Dispose(bool disposing)
+               {
+                       if (disposing && !disposed && host != null) {
+                               if (HasKeyBinding)
+                                       host.KeyDown -= key_handler;
+                               if (HasCanExecuteBinding)
+                                       host.ValueChanged -= canExecuteBinding_handler;
+                       }
+                       disposed = true;
+               }
+               public void Dispose()
+               {
+                       // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+                       Dispose(disposing: true);
+                       GC.SuppressFinalize(this);
+               }
+               #endregion
        }
 }
index d323ae85897d7e9dc29a04a1c15e900bb0cd939a..6c5a76ba6866b106d53776e33231253a26940b10 100644 (file)
@@ -9,7 +9,8 @@ using System.Linq;
 namespace Crow {
        public class CommandGroup : CommandBase, IEnumerable, IList<CommandBase>
        {
-               public IList<CommandBase> Commands;
+               public IList<CommandBase> Commands { get; private set; }
+
 
                public CommandGroup () {
                        Commands = new ObservableList<CommandBase>();
@@ -25,6 +26,9 @@ namespace Crow {
                public CommandGroup (params CommandBase[] commands) {
                        Commands = new ObservableList<CommandBase>(commands);
                }
+               public CommandGroup (ICommandHost host) {
+
+               }
 
 
                public int Count => Commands.Count;
@@ -61,7 +65,10 @@ namespace Crow {
                        foreach  (CommandBase c in items)
                                Commands.Remove (c);
                }
-               ///
+               /// <summary>
+               /// Set boolean value for the CanExecute state of all commands
+               /// </summary>
+               /// <param name="canExecute"></param>
                public void ToggleAllCommand (bool canExecute) {
                        foreach  (ActionCommand c in Commands.OfType<ActionCommand> ())
                                c.CanExecute = canExecute;
diff --git a/Crow/src/Command/KeyBinding.cs b/Crow/src/Command/KeyBinding.cs
new file mode 100644 (file)
index 0000000..2c85404
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2021-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using EnumsNET;
+using Glfw;
+
+namespace Crow
+{
+    public class KeyBinding
+    {
+               public readonly Key Key;
+               public readonly Modifier Modifiers;
+               public KeyBinding (Key key, Modifier modifiers = 0) {
+            Key = key;
+            Modifiers = modifiers;
+        }
+        public KeyBinding Parse (string str) {
+            string[] tmp = str.Split (',');
+            if (Enums.TryParse<Key> (tmp[0], out Key k)) {
+                if (tmp.Length > 1 && FlagEnums.TryParseFlags<Modifier> (tmp[1], out Modifier mods))
+                    return new KeyBinding (k, mods);
+                else
+                    return new KeyBinding (k);
+            }
+            return default;
+        }
+        public override string ToString () => $"{FlagEnums.FormatFlags (Modifiers, "+")} + {Key}";
+    }
+}
\ No newline at end of file
index 6182195ca31da94c8353add48496d11e77e2cb8a..45032a22693aaaf4cc0c64f7c567a86635d36266 100644 (file)
@@ -13,54 +13,33 @@ namespace Crow {
        /// <summary>
        /// helper class to bind in one step icon, caption, action, and validity tests to a controls
        /// </summary>
-       public class ToggleCommand : Command, IToggle, IDisposable
+       public class ToggleCommand : Command, IToggle
        {
                #region CTOR
-               public ToggleCommand () {}
-               public ToggleCommand (object instance, string memberName, string icon = null, bool _canExecute = true)
-                       : this ("", instance, memberName, icon, _canExecute) { }
-               public ToggleCommand (string caption, object instance, string memberName, string icon = null, bool _canExecute = true)
-                       : base (caption, icon, _canExecute)
+               public ToggleCommand (ICommandHost _host, string caption, Binding<bool> toggleBinding, string icon = null, KeyBinding _keyBinding = null,
+                                               Binding<bool> _canExecuteBinding = null)
+                       : base (_host, caption, icon, _keyBinding, _canExecuteBinding)
                {
-                       this.instance = instance;
-                       this.memberName = memberName;
-                       MemberInfo mbi = instance.GetType().GetMember (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault();
-
-                       if (mbi is PropertyInfo pi) {
-                               delSet = (Action<bool>)Delegate.CreateDelegate (typeof (Action<bool>), instance, pi.GetSetMethod ());
-                               delGet = (Func<bool>)Delegate.CreateDelegate (typeof (Func<bool>), instance, pi.GetGetMethod ());
-                       } else if (mbi is FieldInfo fi) {
-                               DynamicMethod dm = new DynamicMethod($"{fi.ReflectedType.FullName}_fldset", null, new Type[] { fi.ReflectedType, typeof(bool) }, false);
-                               ILGenerator il = dm.GetILGenerator ();
-                               il.Emit (OpCodes.Ldarg_0);
-                               il.Emit (OpCodes.Ldarg_1);
-                               il.Emit (OpCodes.Stfld, fi);
-
-                               il.Emit(OpCodes.Ret);
-
-                               delSet = (Action<bool>)dm.CreateDelegate (typeof (Action<bool>), instance);
-
-                               dm = new DynamicMethod($"{fi.ReflectedType.FullName}_fldget", typeof(bool), new Type[] { fi.ReflectedType }, false);
-                               il = dm.GetILGenerator ();
-                               il.Emit (OpCodes.Ldarg_0);
-                               il.Emit (OpCodes.Ldfld, fi);
-
-                               il.Emit(OpCodes.Ret);
-
-                               delGet = (Func<bool>)dm.CreateDelegate (typeof (Func<bool>), instance);
-                       } else
-                               throw new Exception ("unsupported member type for ToggleCommand");
-
-                       if (instance is IValueChange ivc)
-                               ivc.ValueChanged +=  instance_valueChanged;
+                       binding = toggleBinding;
+                       delSet = binding.CreateSetter (host);
+                       delGet = binding.CreateGetter (host);
 
+                       host.ValueChanged +=  toggleCommand_host_valueChanged_handler;
+               }
+               public ToggleCommand (ICommandHost _host, string caption, Binding<bool> toggleBinding, string icon = null,
+                                       KeyBinding _keyBinding = null, bool _canExecute = true)
+                       : this (_host, caption, toggleBinding, icon, _keyBinding, null)
+               {
                        CanExecute = _canExecute;
                }
-               void instance_valueChanged (object sender, ValueChangeEventArgs e) {
-                       if (e.MemberName != memberName)
-                               return;
-                       //Console.WriteLine ($"ToggleCommand valueChanged triggered => {e.NewValue}");
+               #endregion
+               Binding<bool> binding;
+               Action<bool> delSet;
+               Func<bool> delGet;
 
+               void toggleCommand_host_valueChanged_handler (object sender, ValueChangeEventArgs e) {
+                       if (e.MemberName != binding.SourceMember)
+                               return;
                        bool tog = (bool)e.NewValue;
                        NotifyValueChanged ("IsToggled", tog);
                        if (tog)
@@ -69,12 +48,6 @@ namespace Crow {
                                ToggleOff.Raise (this, null);
 
                }
-               #endregion
-               object instance;
-               string memberName;
-               Action<bool> delSet;
-               Func<bool> delGet;
-               bool disposedValue;
 
 
                /// <summary>
@@ -92,7 +65,6 @@ namespace Crow {
                }
 
                #region IToggle implementation
-
                public event EventHandler ToggleOn;
                public event EventHandler ToggleOff;
                public BooleanTestOnInstance IsToggleable {get; set; }
@@ -113,24 +85,13 @@ namespace Crow {
                }
                #endregion
 
-               protected virtual void Dispose(bool disposing)
+               #region IDispose implementation
+               protected override void Dispose(bool disposing)
                {
-                       if (!disposedValue)
-                       {
-                               if (disposing)
-                               {
-                                       if (instance is IValueChange ivc)
-                                               ivc.ValueChanged -=  instance_valueChanged;
-                               }
-                               disposedValue = true;
-                       }
-               }
-
-               public void Dispose()
-               {
-                       // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
-                       Dispose(disposing: true);
-                       GC.SuppressFinalize(this);
+                       if (disposing && !disposed && host != null)
+                               host.ValueChanged -=  toggleCommand_host_valueChanged_handler;
+                       base.Dispose (true);
                }
+               #endregion
        }
 }
index 8cd72d97281307a13260b3f98b7f926eb4a36d26..6fa2ad2d23309692786ef9c1947cf5d74a252d71 100644 (file)
@@ -12,7 +12,7 @@ namespace Crow
                public event EventHandler<ValueChangeEventArgs> ValueChanged;
                public virtual void NotifyValueChanged(string MemberName, object _value)
                {
-                       if (ValueChanged != null)                               
+                       if (ValueChanged != null)
                                ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value));
                }
                #endregion
@@ -23,7 +23,7 @@ namespace Crow
                        Layouting,
                        Drawing
         }
-               public static PerformanceMeasure[] Measures;            
+               public static PerformanceMeasure[] Measures;
 
                [Conditional("MEASURE_TIME")]
                public static void InitMeasures () {
@@ -36,7 +36,7 @@ namespace Crow
                [Conditional ("MEASURE_TIME")]
                public static void Notify () {
             for (int i = 0; i < 4; i++)
-                               Measures[i].NotifyChanges ();            
+                               Measures[i].NotifyChanges ();
                }
                [Conditional ("MEASURE_TIME")]
                public static void Begin (Kind kind) {
@@ -80,7 +80,7 @@ namespace Crow
                        }
                }
 
-               void computeStats(){                    
+               void computeStats(){
                        current = timer.ElapsedMilliseconds;
                        if (current < cancelLimit)
                                return;
@@ -89,7 +89,7 @@ namespace Crow
                        if (timer.ElapsedMilliseconds < minimum)
                                minimum = timer.ElapsedMilliseconds;
                        if (timer.ElapsedMilliseconds > maximum)
-                               maximum = timer.ElapsedMilliseconds;                    
+                               maximum = timer.ElapsedMilliseconds;
                }
                void ResetStats(){
                        Debug.WriteLine("reset measure cpt:{0}",cptMeasures);
index ebbb8d223cb5d9577d7747076fb764e0a4f08495..866e32a951e74623b898528a2b0e2f4dd7703210 100644 (file)
@@ -10,7 +10,7 @@ namespace Crow
         Vertical
     }
 
-       public enum Alignment 
+       public enum Alignment
     {
         Top = 0x01,
         Left = 0x02,
@@ -106,7 +106,7 @@ namespace Crow
                ur_angle,
                watch,
                X_cursor,
-               xterm,                  
+               xterm,
        }
        /// <summary>
        /// Cursor shape use in Sliders
index 2d8553b8b74e8f85564fd20dafb9a0de2f65cb82..7f83cfaf2deadbb6a2e4ce061f24a34257cf9337 100644 (file)
@@ -19,7 +19,7 @@ namespace Crow
        public class ListClearEventArg : EventArgs
        {
                public IEnumerable<object> Elements;
-               public ListClearEventArg (IEnumerable<object> elements) {                       
+               public ListClearEventArg (IEnumerable<object> elements) {
                        Elements = elements;
                }
        }
index 7fe3d4c1ccb66c072b65e80712b9f3004901490c..2d344c7339c7e398013e61210de5ed62e1b76d6d 100644 (file)
@@ -23,7 +23,7 @@ namespace Crow
                        public double Offset;
                        public Color Color;
 
-                       public ColorStop(double offset, Color color){ 
+                       public ColorStop(double offset, Color color){
                                Offset = offset;
                                Color = color;
                        }
@@ -31,7 +31,7 @@ namespace Crow
                        {
                                if (string.IsNullOrEmpty (s))
                                        return null;
-                               
+
                                string[] parts = s.Trim ().Split (':');
 
                                if (parts.Length > 2)
@@ -80,7 +80,7 @@ namespace Crow
                                        continue;
                                grad.AddColorStop (cs.Offset, cs.Color);
                        }
-                       
+
                        ctx.SetSource (grad);
                        grad.Dispose ();
                }
index 3daf82ab7627ac387afaf68eaa7e3f9dc3cf7bca..69c74e42e620373f3d82ac18541676a61d157555 100644 (file)
@@ -778,6 +778,7 @@ namespace Crow.IML
                                                eiEvt.RemoveEventHandler (instance, d);
 #if DEBUG_BINDING
                                                Console.WriteLine ("\tremoveEventHandlerByName: {0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+
 #endif
                                        }
                                }
index 23f8559d7e742eeb1b298b9297353b4f9791fb13..30605e78f622a166943c8c9ce9ec6dd3b71b47c4 100644 (file)
@@ -8,33 +8,34 @@ using Glfw;
 namespace Crow
 {
        public class KeyEventArgs : CrowEventArgs
-    {
-               int keyCode=0;
+       {
                Key key;
-               bool repeat;    
+               int scancode;
+               Modifier modifiers;
+               bool repeat;
 
-               public KeyEventArgs(Key _key, bool _repeat)
+               public KeyEventArgs (Key _key, bool _repeat = false)
                {
                        key = _key;
                        repeat = _repeat;
                }
-               public KeyEventArgs(KeyEventArgs args)
+               public KeyEventArgs (Key _key, int _scancode, Modifier _modifiers, bool _repeat = false)
                {
-                   Key = args.Key;
-               }
-               public Key Key
-               {
-                   get { return key; }
-                   internal set { key = value; }
-               }
-               public uint ScanCode
-               {
-                   get { return (uint)keyCode; }
+                       key = _key;
+                       scancode = _scancode;
+                       modifiers = _modifiers;
+                       repeat = _repeat;
                }
-               public bool IsRepeat
+               public KeyEventArgs (KeyEventArgs e)
                {
-                   get { return repeat; }
-                   internal set { repeat = value; }
+                       key = e.Key;
+                       repeat = e.IsRepeat;
+                       scancode = e.ScanCode;
+                       modifiers = e.Modifiers;
                }
-    }
+               public Key Key => key;
+               public int ScanCode => scancode;
+               public Modifier Modifiers => modifiers;
+               public bool IsRepeat => repeat;
+       }
 }
index 9d3badda6e36b75e990f12518ccf1bfe6c0625d2..f84822ebd542fbef60f21273b806e3f2616d4a81 100644 (file)
@@ -26,7 +26,7 @@ namespace Crow
        public class MouseEventArgs : CrowEventArgs
        {
                public readonly int X, Y;
-               public Point Position => new Point (X, Y);              
+               public Point Position => new Point (X, Y);
                public MouseEventArgs () { }
                public MouseEventArgs (int x, int y) {
                        X = x;
@@ -44,7 +44,7 @@ namespace Crow
                }
        }
 
-       public class MouseButtonEventArgs : MouseEventArgs 
+       public class MouseButtonEventArgs : MouseEventArgs
        {
                public readonly MouseButton Button;
                public readonly InputAction Action;
index b46bf018d3468a331bc916ef660d6673fb1930d1..ede2927e9ca2d3fa078f8cd7a4dce5f7f8d8df3d 100644 (file)
@@ -45,7 +45,7 @@ namespace Crow
        /// The resulting surface (a byte array in the OpenTK renderer) is made available and protected with the
        /// RenderMutex of the interface.
        /// </remarks>
-       public class Interface : ILayoutable, IDisposable, IValueChange
+       public class Interface : ILayoutable, IDisposable, ICommandHost
        {
                #region IValueChange implementation
                public event EventHandler<ValueChangeEventArgs> ValueChanged;
@@ -401,12 +401,17 @@ namespace Crow
                        windows [window].OnMouseWheelChanged ((int)yOffset);
                };
                static KeyDelegate HandleKeyDelegate = (IntPtr window, Key key, int scanCode, InputAction action, Modifier modifiers) => {
+                       string localizedKey = Glfw3.GetKeyName (key, scanCode);
+                       if (!string.IsNullOrEmpty (localizedKey) && EnumsNET.Enums.TryParse<Key> (localizedKey, true, out Key locKey))
+                               key = locKey;
+
                        if (action == InputAction.Release)
-                               windows [window].OnKeyUp (key);
+                               windows [window].OnKeyUp (new KeyEventArgs (key, scanCode, modifiers));
                         else
-                               windows [window].OnKeyDown (key);
+                               windows [window].OnKeyDown (new KeyEventArgs (key, scanCode, modifiers));
                };
                static CharDelegate HandleCharDelegate = (IntPtr window, CodePoint codepoint) => {
+                       Console.WriteLine ($"Char: cp:{codepoint.Value} -> '{codepoint}'");
                        windows [window].OnKeyPress (codepoint.ToChar());
                };
                static WindowSizeDelegate HandleWindowSizeDelegate = (IntPtr window, int Width, int Height) => {
@@ -604,13 +609,15 @@ namespace Crow
 
                public event EventHandler StartDragOperation;
                public event EventHandler EndDragOperation;
+               public event EventHandler<KeyEventArgs> KeyDown;
+               public event EventHandler<KeyEventArgs> KeyUp;
+
                //public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
                //public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
                //public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
                //public event EventHandler<MouseButtonEventArgs> MouseClick;
                //public event EventHandler<MouseMoveEventArgs> MouseMove;
                //public event EventHandler<KeyEventArgs> KeyDown;
-               //public event EventHandler<KeyEventArgs> KeyUp;
                //public event EventHandler<KeyPressEventArgs> KeyPress;
                /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
                public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
@@ -1865,26 +1872,22 @@ namespace Crow
 
                public virtual bool OnKeyPress (char c)
                {
-                       if (_focusedWidget == null)
-                               return false;
-                       _focusedWidget.onKeyPress (_focusedWidget, new KeyPressEventArgs (c));
-                       return true;
+                       KeyPressEventArgs e = new KeyPressEventArgs (c);
+                       if (_focusedWidget != null)
+                               _focusedWidget.onKeyPress (_focusedWidget, e);
+                       return e.Handled;
                }
-               public virtual bool OnKeyUp (Key key)
+               public virtual bool OnKeyUp (KeyEventArgs e)
                {
-                       if (_focusedWidget == null)
-                               return false;
-                       _focusedWidget.onKeyUp (_focusedWidget, new KeyEventArgs (key, false));
-                       return true;
-
-
-                       //                      if (keyboardRepeatThread != null) {
-                       //                              keyboardRepeatOn = false;
-                       //                              keyboardRepeatThread.Abort();
-                       //                              keyboardRepeatThread.Join ();
-                       //                      }
+                       if (!e.Handled) {
+                               if (KeyUp != null)
+                                       KeyUp.Invoke (this, e);
+                               if (!e.Handled && _focusedWidget != null)
+                                       _focusedWidget.onKeyUp (_focusedWidget, e);
+                       }
+                       return e.Handled;
                }
-               public virtual bool OnKeyDown (Key key)
+               public virtual bool OnKeyDown (KeyEventArgs e)
                {
 #if DEBUG_STATS
                        if (Shift && key == Key.F1) {
@@ -1912,18 +1915,15 @@ namespace Crow
                                ").DataSource = this;
                        }
 #endif
+                       lastKeyDownEvt = new KeyEventArgs (e);
 
-                       //Keyboard.SetKeyState((Crow.Key)Key,true);
-                       lastKeyDownEvt = new KeyEventArgs (key, true);
-
-                       if (_focusedWidget == null)
-                               return false;
-                       _focusedWidget.onKeyDown (_focusedWidget, new KeyEventArgs (key, false));
-                       return true;
-
-                       //                      keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc);
-                       //                      keyboardRepeatThread.IsBackground = true;
-                       //                      keyboardRepeatThread.Start ();
+                       if (!e.Handled) {
+                               if (KeyDown != null)
+                                       KeyDown.Invoke (this, e);
+                               if (!e.Handled && _focusedWidget != null)
+                                       _focusedWidget.onKeyDown (_focusedWidget, e);
+                       }
+                       return e.Handled;
                }
 
                public bool IsKeyDown (Key key) => Glfw3.GetKey (hWin, key) == InputAction.Press;
index 6c0056295c52280c17fd7c38ae357bbdbeb34280..a6b57687eb4ca9560b589a856a7283e6aa981437 100644 (file)
@@ -119,11 +119,5 @@ namespace Crow
                        }
                        NotifyValueChanged (mName, e.NewValue);
                }
-               protected override void Dispose(bool disposing)
-               {
-                       if (command is IDisposable dis)
-                               dis.Dispose ();
-                       base.Dispose(disposing);
-               }
        }
 }
index e01fe269474551d677a5e267aca4c771e4e07e7d..9a16bf872f5fa40b604d482e71d4bd71348b0619 100644 (file)
@@ -28,7 +28,7 @@ namespace Crow
                public event EventHandler<TextChangeEventArgs> TextChanged;
 
                public virtual void OnTextChanged(Object sender, TextChangeEventArgs e)
-               {                       
+               {
                        TextChanged.Raise (this, e);
                }
         //TODO:change protected to private
@@ -36,11 +36,11 @@ namespace Crow
                #region private and protected fields
                protected string _text = "";
         TextAlignment _textAlignment;
-               bool _multiline;                
+               bool _multiline;
                Color selBackground;
                Color selForeground;
 
-               int targetColumn = -1;//handle line changes with long->short->long line length sequence.                
+               int targetColumn = -1;//handle line changes with long->short->long line length sequence.
 
                protected CharLocation? hoverLoc = null;
                protected CharLocation? currentLoc = null;
@@ -127,7 +127,7 @@ namespace Crow
                /// <summary>
                /// If measure is not 'Fit', align text inside the bounds of this label.
                /// </summary>
-               [DefaultValue(TextAlignment.Left)]              
+               [DefaultValue(TextAlignment.Left)]
                public TextAlignment TextAlignment
         {
             get { return _textAlignment; }
@@ -142,7 +142,7 @@ namespace Crow
                                RegisterForRedraw ();
                                NotifyValueChangedAuto (_textAlignment);
                        }
-        }              
+        }
                /// <summary>
                /// Text to display in this label. May include linebreaks if Multiline is 'true'.
                /// If Multiline is false, linebreaks will be treated as unrecognized unicode char.
@@ -201,12 +201,12 @@ namespace Crow
                                RegisterForGraphicUpdate();
                        }
                }
-               
+
 
                /// <summary>
                /// Moves cursor one char to the left.
                /// </summary>
-               /// <returns><c>true</c> if move succeed</returns>              
+               /// <returns><c>true</c> if move succeed</returns>
                public bool MoveLeft(){
                        //targetColumn = -1;
                        CharLocation loc = CurrentLoc.Value;
@@ -228,7 +228,7 @@ namespace Crow
                        } else
                                CurrentLoc = new CharLocation (loc.Line, loc.Column + 1);
                        return true;
-               }               
+               }
                public bool LineMove (int lineDiff) {
                        CharLocation loc = CurrentLoc.Value;
                        int newLine = Math.Min (Math.Max (0, loc.Line + lineDiff), lines.Count - 1);
@@ -251,7 +251,7 @@ namespace Crow
         }
                protected int visibleLines => (int)((double)ClientRectangle.Height / (fe.Ascent + fe.Descent));
                public void GotoWordStart(){
-                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value);                 
+                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value);
                        //skip white spaces
                        while (pos > 0 && !char.IsLetterOrDigit (_text[pos-1]))
                                pos--;
@@ -267,11 +267,11 @@ namespace Crow
                        while (pos < _text.Length - 1 && char.IsLetterOrDigit (_text[pos]))
                                pos++;
                        CurrentLoc = lines.GetLocation (pos);
-               }               
+               }
 
                protected void detectLineBreak () {
                        if (!_multiline)
-                               return;                 
+                               return;
                        mixedLineBreak = false;
 
                        if (lines.Count == 0 || lines[0].LineBreakLength == 0) {
@@ -288,8 +288,8 @@ namespace Crow
                 }
                        }
         }
-               
-               protected void getLines () {                    
+
+               protected void getLines () {
                        if (lines == null)
                                lines = new LineCollection (_multiline ? 4 : 1);
                        else
@@ -513,7 +513,7 @@ namespace Crow
                        }
                        if (!CurrentLoc.Value.HasVisualX) {
                                setFontForContext (ctx);
-                               lock (linesMutex) {                                     
+                               lock (linesMutex) {
                                        if (currentLoc?.Column < 0) {
                                                updateLocation (ctx, ClientRectangle.Width, ref currentLoc);
                                                NotifyValueChanged ("CurrentColumn", CurrentColumn);
@@ -534,7 +534,7 @@ namespace Crow
                        //}
                        Rectangle c = ScreenCoordinates (textCursor.Value + Slot.Position + ClientRectangle.Position);
                        ctx.ResetClip ();
-                       Foreground.SetAsSource (IFace, ctx, c);                 
+                       Foreground.SetAsSource (IFace, ctx, c);
                        ctx.LineWidth = 1.0;
                        ctx.MoveTo (0.5 + c.X, c.Y);
                        ctx.LineTo (0.5 + c.X, c.Bottom);
@@ -613,7 +613,7 @@ namespace Crow
                                        return false;
                        }
                        try {
-                               bool result = base.UpdateLayout (layoutType);                           
+                               bool result = base.UpdateLayout (layoutType);
                                return result;
                        } finally {
                                System.Threading.Monitor.Exit (linesMutex);
@@ -635,7 +635,7 @@ namespace Crow
                        DbgLogger.EndEvent(DbgEvtType.GOMeasure);
                        return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width);
                }
-               
+
                protected override void onDraw (Context gr)
                {
                        DbgLogger.StartEvent(DbgEvtType.GODraw, this);
@@ -643,12 +643,12 @@ namespace Crow
                        base.onDraw (gr);
 
                        setFontForContext (gr);
-                       
+
                        if (!textMeasureIsUpToDate) {
                                lock (linesMutex)
                                        measureTextBounds (gr);
             }
-                       
+
                        if (ClipToClientRect) {
                                gr.Save ();
                                CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
@@ -657,7 +657,7 @@ namespace Crow
 
                        lock (linesMutex)
                                drawContent (gr);
-                       
+
                        if (ClipToClientRect)
                                gr.Restore ();
 
@@ -670,7 +670,7 @@ namespace Crow
                {
                        base.onFocused (sender, e);
                        if (CurrentLoc == null) {
-                               selectionStart = new CharLocation (0, 0);                               
+                               selectionStart = new CharLocation (0, 0);
                                CurrentLoc = new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
                        }
                        RegisterForRedraw ();
@@ -683,7 +683,7 @@ namespace Crow
         public override void onMouseEnter (object sender, MouseMoveEventArgs e) {
             base.onMouseEnter (sender, e);
                        if (Focusable)
-                               IFace.MouseCursor = MouseCursor.ibeam;                  
+                               IFace.MouseCursor = MouseCursor.ibeam;
                }
         public override void onMouseMove (object sender, MouseMoveEventArgs e)
                {
@@ -692,16 +692,16 @@ namespace Crow
                        updateHoverLocation (ScreenPointToLocal (e.Position));
 
                        if (HasFocus && IFace.IsDown (MouseButton.Left)) {
-                               CurrentLoc = hoverLoc;                          
-                               RegisterForRedraw ();                           
+                               CurrentLoc = hoverLoc;
+                               RegisterForRedraw ();
                        }
-               }               
+               }
                public override void onMouseDown (object sender, MouseButtonEventArgs e)
                {
                        if (e.Button == Glfw.MouseButton.Left) {
                                targetColumn = -1;
-                               if (HasFocus) {                                 
-                                       if (!IFace.Shift)                                                
+                               if (HasFocus) {
+                                       if (!IFace.Shift)
                                                selectionStart = hoverLoc;
                                        else if (!selectionStart.HasValue)
                                                selectionStart = CurrentLoc;
@@ -709,7 +709,7 @@ namespace Crow
                                        IFace.forceTextCursor = true;
                                        RegisterForRedraw ();
                                        e.Handled = true;
-                               }                                       
+                               }
                        }
                        base.onMouseDown (sender, e);
 
@@ -719,7 +719,7 @@ namespace Crow
                {
                        base.onMouseUp (sender, e);
                        if (e.Button != MouseButton.Left || !HasFocus || !selectionStart.HasValue)
-                               return;                 
+                               return;
                        if (selectionStart.Value == CurrentLoc.Value)
                                selectionStart = null;
                }
@@ -730,7 +730,7 @@ namespace Crow
                                return;
 
                        GotoWordStart ();
-                       selectionStart = CurrentLoc;                    
+                       selectionStart = CurrentLoc;
                        GotoWordEnd ();
                        RegisterForRedraw ();
                }
@@ -738,7 +738,7 @@ namespace Crow
 
                #region Keyboard handling
                public override void onKeyDown (object sender, KeyEventArgs e) {
-                       
+
                        switch (e.Key) {
                        case Key.Escape:
                                selectionStart = null;
@@ -794,7 +794,7 @@ namespace Crow
                                return;
                        }
                        IFace.forceTextCursor = true;
-                       e.Handled = true;                       
+                       e.Handled = true;
                }
                #endregion
 
index c861441f27cdb4cfe5b5da8ccb87111f1a51c084..e91600954aa87f9dc49bebec63e2660227364afc 100644 (file)
@@ -165,12 +165,6 @@ namespace Crow
                                tmp = tmp.LogicalParent as MenuItem;
                        }
                }
-               protected override void Dispose(bool disposing)
-               {
-                       if (command is IDisposable dis)
-                               dis.Dispose ();
-                       base.Dispose(disposing);
-               }
        }
 }
 
index b08e18570ad9137f7a586b0b5ffca6172bfbbdc2..b5e9fbc2f7a63c92fb6cc88f623695986093a5f8 100644 (file)
@@ -29,7 +29,7 @@ namespace Crow
                                return true;
                        if (child == null)
                                return false;
-                       return child.FindByDesignID (designID, out go);                                 
+                       return child.FindByDesignID (designID, out go);
                }
                #endif
                protected Widget child;
@@ -59,7 +59,7 @@ namespace Crow
                        if (child != null) {
                                child.Parent = this;
                                child.LayoutChanged += OnChildLayoutChanges;
-                               contentSize = child.Slot.Size;                          
+                               contentSize = child.Slot.Size;
                                child.RegisterForLayouting (LayoutingType.Sizing);
                        }
                }
@@ -89,7 +89,7 @@ namespace Crow
                }
                public override bool Contains (Widget goToFind)
                {
-                       return child == goToFind ? true : 
+                       return child == goToFind ? true :
                                child == null ? false : child.Contains(goToFind);
                }
                public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
@@ -116,7 +116,7 @@ namespace Crow
                                                        contentSize.Height = child.measureRawSize (LayoutingType.Height);
                                                break;
                                        }
-                                       DbgLogger.SetMsg(DbgEvtType.GOMeasure, $"{lt} contentSize:{contentSize}");                                      
+                                       DbgLogger.SetMsg(DbgEvtType.GOMeasure, $"{lt} contentSize:{contentSize}");
                                }
                                return base.measureRawSize (lt);
                        } finally {
@@ -171,7 +171,7 @@ namespace Crow
                        child.RegisterForLayouting (ltChild);
                }
                public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
-               {                       
+               {
                        Widget g = sender as Widget;
                        if (arg.LayoutType == LayoutingType.Width) {
                                contentSize.Width = g.Slot.Width;
@@ -220,7 +220,7 @@ namespace Crow
                                                gr.Rectangle(Clipping.GetRectangle(i));
                                        gr.ClipPreserve();
                                        gr.Operator = Operator.Clear;
-                                       gr.Fill();                                      
+                                       gr.Fill();
                                        gr.Operator = Operator.Over;
 
                                        onDraw (gr);
@@ -237,8 +237,8 @@ namespace Crow
                {
                        base.checkHoverWidget (e);
 
-                       if (child != null) 
-                               if (child.MouseIsIn (e.Position)) 
+                       if (child != null)
+                               if (child.MouseIsIn (e.Position))
                                        child.checkHoverWidget (e);
                }
                #endregion
index aebcc071f57df7de028c3d34542c76a76225bece..12d6ce1e349a9c87854cc6fbfe21b18c5ef47e16 100644 (file)
@@ -134,7 +134,7 @@ namespace Crow
                }
 
                /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
-               public override void onMouseWheel (object sender, MouseWheelEventArgs e) {                      
+               public override void onMouseWheel (object sender, MouseWheelEventArgs e) {
                        e.Handled = true;
                        if (IFace.Shift)
                                ScrollX += e.Delta * MouseWheelSpeed;
@@ -142,10 +142,10 @@ namespace Crow
                                ScrollY -= e.Delta * MouseWheelSpeed;
                        else
                                e.Handled = false;
-                       
+
                        base.onMouseWheel (sender, e);
                }
-               public override void onMouseMove (object sender, MouseMoveEventArgs e) {            
+               public override void onMouseMove (object sender, MouseMoveEventArgs e) {
                        if (!HasFocus || !IFace.IsDown (MouseButton.Left)) {
                                base.onMouseMove (sender, e);
                                return;
@@ -215,8 +215,8 @@ namespace Crow
                                        return null;
                        } else if (cursor.Right < 0 || cursor.X > cb.Width || cursor.Y < 0 || cursor.Bottom > cb.Height)
                                return null;
-                       
-                       return cursor;            
+
+                       return cursor;
                }
 
                void updateMaxScrolls (LayoutingType layout) {
@@ -244,7 +244,7 @@ namespace Crow
                        TextSpan selection = Selection;
                        if (selection.IsEmpty)
                                return;
-                       IFace.Clipboard = SelectedText;         
+                       IFace.Clipboard = SelectedText;
                }
                public virtual void Paste () {
                        TextSpan selection = Selection;
@@ -272,8 +272,8 @@ namespace Crow
                                if (selection.IsEmpty) {
                                        if (selection.Start == Text.Length)
                                                return;
-                                       if (CurrentLoc.Value.Column >= lines[CurrentLoc.Value.Line].Length) 
-                                               update (new TextChange (selection.Start, lines[CurrentLoc.Value.Line].LineBreakLength, ""));                        
+                                       if (CurrentLoc.Value.Column >= lines[CurrentLoc.Value.Line].Length)
+                                               update (new TextChange (selection.Start, lines[CurrentLoc.Value.Line].LineBreakLength, ""));
                                        else
                                                update (new TextChange (selection.Start, 1, ""));
                                } else {
@@ -345,7 +345,7 @@ namespace Crow
                                src.Slice (0, change.Start).CopyTo (tmp);
                                change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
                                src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
-                       
+
                                _text = tmp.ToString ();
                                lines.Update (change);
                                //lines.Update (_text);
@@ -358,7 +358,7 @@ namespace Crow
 
                        NotifyValueChanged ("Text", Text);
                        OnTextChanged (this, new TextChangeEventArgs (change));
-                       
+
                        RegisterForGraphicUpdate ();
                }
                protected override string LogName => "tb";
index 4dbcb34070993f2b4721310ab23d274e212ff34c..0b5b4463e7a1d36b8f41b6be6838c67d6e18aa3c 100644 (file)
@@ -2060,19 +2060,19 @@ namespace Crow
                public virtual void onKeyDown(object sender, KeyEventArgs e){
                        if (KeyDown != null)
                                KeyDown.Invoke (this, e);
-                       else if (!e.Handled)
+                       else if (!e.Handled && BubbleMouseEvent.HasFlag (DeviceEventType.KeyDown))
                                FocusParent?.onKeyDown (sender, e);
                }
                public virtual void onKeyUp(object sender, KeyEventArgs e){
                        if (KeyUp != null)
                                KeyUp.Invoke (this, e);
-                       else if (!e.Handled)
+                       else if (!e.Handled && BubbleMouseEvent.HasFlag (DeviceEventType.KeyUp))
                                FocusParent?.onKeyUp (sender, e);
                }
                public virtual void onKeyPress(object sender, KeyPressEventArgs e){
                        if (KeyPress != null)
                                KeyPress.Invoke (this, e);
-                       else if (!e.Handled)
+                       else if (!e.Handled && BubbleMouseEvent.HasFlag (DeviceEventType.KeyPress))
                                FocusParent?.onKeyPress (sender, e);
                }
                #endregion
index 5aa36fa76fb0a232cd5de86418dfa28706c8a17b..cb094e4aadc4c559d0f0e9920aebff1668ef26ad 100644 (file)
@@ -108,9 +108,9 @@ namespace ShowCase
                }
 
 
-        public override bool OnKeyDown (Key key) {
+        public override bool OnKeyDown (KeyEventArgs e) {
 
-            switch (key) {
+            switch (e.Key) {
             case Key.F5:
                 Load ("#ShowCase.DebugLog.crow").DataSource = this;
                 return true;
@@ -129,7 +129,7 @@ namespace ShowCase
                                }
                 return true;
             }
-            return base.OnKeyDown (key);
+            return base.OnKeyDown (e);
         }
     }
 }
\ No newline at end of file
index de32059e9ec14251e1081a7dc7372f0c00017178..c64fa74090826c50246fce16647348a4f468148d 100644 (file)
@@ -25,7 +25,7 @@
                                                                <ListItem ContextCommands="{GetCommands}"
                                                                                Selected="{/exp.Background=${ControlHighlight}}"
                                                                                Unselected="{/exp.Background=Transparent}">
-                                                                       <Expandable Name="exp" Caption="{Name}" MouseDoubleClick="/onClickForExpand" >
+                                                                       <Expandable Name="exp" Caption="{Name}" MouseDoubleClick="/onClickForExpand" BubbleMouseEvent="MouseWheel|Keyboard|ButtonDown">
                                                                                <Template>
                                                                                        <VerticalStack>
                                                                                                <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
index c093d34599329b42b3aa66c3bcca475ef1129a42..e56914f885cdc0d700934fb20ef88cd01f8d2ea1 100644 (file)
@@ -19,7 +19,7 @@ namespace Crow
                XmlSource source;
                object TokenMutex = new object();
 
-               void parse () {                 
+               void parse () {
                        XmlSource tmp = new XmlSource(_text);
                        lock(TokenMutex)
                                source = tmp;
@@ -41,7 +41,7 @@ namespace Crow
                                if (suggestions == null || suggestions.Count == 0)
                                        hideOverlay ();
                                else
-                                       showOverlay ();                         
+                                       showOverlay ();
                        }
                }
                bool suggestionsActive => overlay != null && overlay.IsVisible;
@@ -58,9 +58,9 @@ namespace Crow
                                                m.GetCustomAttribute<XmlIgnoreAttribute>() == null);
                }
                MemberInfo getCrowTypeMember (string crowTypeName, string memberName) {
-                       Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName);                  
+                       Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName);
                        return crowType.GetMember (memberName, BindingFlags.Public | BindingFlags.Instance).FirstOrDefault ();
-               }               
+               }
 
                public override void OnTextChanged(object sender, TextChangeEventArgs e)
                {
@@ -68,7 +68,7 @@ namespace Crow
                        //Task.Run(()=>parse());
 
                        parse();
-                       
+
                        if (!disableSuggestions && HasFocus)
                                tryGetSuggestions ();
 
@@ -77,7 +77,7 @@ namespace Crow
                void tryGetSuggestions () {
                        if (!currentLoc.HasValue)
                                return;
-                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value); 
+                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value);
                        currentToken = source.FindTokenIncludingPosition (pos);
                        currentNode = source.FindNodeIncludingPosition (pos);
                        Console.WriteLine ($"Current Token: {currentToken} Current Node: {currentNode}");
@@ -109,7 +109,7 @@ namespace Crow
                                                                        else if (pi.PropertyType == typeof (Measure))
                                                                                Suggestions = (new string[] {"Stretched", "Fit"}).
                                                                                        Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList ();
-                                                                       else if (pi.PropertyType == typeof (Fill)) 
+                                                                       else if (pi.PropertyType == typeof (Fill))
                                                                                Suggestions = EnumsNET.Enums.GetValues<Colors> ()
                                                                                        .Where (s => s.ToString().StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList ();
                                                                }
@@ -123,7 +123,7 @@ namespace Crow
                                                                                Suggestions = Enum.GetNames (pi.PropertyType).ToList ();
                                                                        else if (pi.PropertyType == typeof(bool))
                                                                                Suggestions = new List<string> (new string[] {"true", "false"});
-                                                                       else if (pi.PropertyType == typeof (Fill)) 
+                                                                       else if (pi.PropertyType == typeof (Fill))
                                                                                Suggestions = EnumsNET.Enums.GetValues<Colors> ().ToList ();
                                                                        else if (pi.PropertyType == typeof (Measure))
                                                                                Suggestions = new List<string> (new string[] {"Stretched", "Fit"});
@@ -131,10 +131,10 @@ namespace Crow
                                                        }
                                                }
                                        }
-                               }                       
-                       } else if (currentToken.Type != TokenType.AttributeValueClose && 
-                                       currentToken.Type != TokenType.EmptyElementClosing && 
-                                       currentToken.Type != TokenType.ClosingSign && 
+                               }
+                       } else if (currentToken.Type != TokenType.AttributeValueClose &&
+                                       currentToken.Type != TokenType.EmptyElementClosing &&
+                                       currentToken.Type != TokenType.ClosingSign &&
                                        currentNode is ElementStartTagSyntax eltStartTag) {
                                if (currentToken.Type == TokenType.AttributeName)
                                        Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text))
@@ -157,39 +157,39 @@ namespace Crow
                                        overlay = IFace.LoadIMLFragment<ListBox>(@"
                                                <ListBox Style='suggestionsListBox' Data='{Suggestions}' UseLoadingThread='False' >
                                                        <ItemTemplate>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <Label Text='{}' HorizontalAlignment='Left' />
-                                                               </ListItem>                                                     
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                        <ItemTemplate DataType='System.Reflection.MemberInfo'>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <HorizontalStack>
                                                                                <Image Picture='{GetIcon}' Width='16' Height='16'/>
                                                                                <Label Text='{Name}' HorizontalAlignment='Left' />
                                                                        </HorizontalStack>
-                                                               </ListItem>                                                     
-                                                       </ItemTemplate>                                                 
+                                                               </ListItem>
+                                                       </ItemTemplate>
                                                        <ItemTemplate DataType='Colors'>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <HorizontalStack>
                                                                                <Widget Background='{}' Width='20' Height='14'/>
                                                                                <Label Text='{}' HorizontalAlignment='Left' />
                                                                        </HorizontalStack>
-                                                               </ListItem>                                                     
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                </ListBox>
                                        ");
                                        overlay.DataSource = this;
-                                       overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;                               
+                                       overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;
                                } else
                                        overlay.IsVisible = true;
-                               overlay.RegisterForLayouting(LayoutingType.Sizing);     
+                               overlay.RegisterForLayouting(LayoutingType.Sizing);
                        }
                }
                void hideOverlay () {
@@ -197,7 +197,7 @@ namespace Crow
                                return;
                        overlay.IsVisible = false;
                }
-               void completeToken () {                 
+               void completeToken () {
                        string selectedSugg = overlay.SelectedItem is MemberInfo mi ?
                                mi.Name : overlay.SelectedItem?.ToString ();
                        if (selectedSugg == null)
@@ -208,15 +208,15 @@ namespace Crow
                                update (new TextChange (currentToken.End, 0, selectedSugg));
                        else if (currentToken.Type == TokenType.AttributeName && currentNode is AttributeSyntax attrib) {
                                        if (attrib.ValueToken.HasValue) {
-                                               TextChange tc = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);                                         
+                                               TextChange tc = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
                                                update (tc);
                                                selectionStart = lines.GetLocation (attrib.ValueToken.Value.Start + tc.CharDiff + 1);
                                                CurrentLoc = lines.GetLocation (attrib.ValueToken.Value.End + tc.CharDiff - 1);
                                        } else {
                                                update (new TextChange (currentToken.Start, currentToken.Length, selectedSugg + "=\"\""));
                                                MoveLeft ();
-                                       }                                       
-                       } else 
+                                       }
+                       } else
                                update (new TextChange (currentToken.Start, currentToken.Length, selectedSugg));
                        hideOverlay ();
                }
@@ -224,7 +224,7 @@ namespace Crow
                        hideOverlay ();
                        base.onMouseDown (sender, e);
                }
-               
+
                public override void onKeyDown(object sender, KeyEventArgs e)
                {
                        TextSpan selection = Selection;
@@ -264,7 +264,7 @@ namespace Crow
                                disableSuggestions = true;
 
                                if (IFace.Shift) {
-                                       for (int l = lineStart; l <= lineEnd; l++) {                            
+                                       for (int l = lineStart; l <= lineEnd; l++) {
                                                if (Text[lines[l].Start] == '\t')
                                                        update (new TextChange (lines[l].Start, 1, ""));
                                                else if (Char.IsWhiteSpace (Text[lines[l].Start])) {
@@ -276,10 +276,10 @@ namespace Crow
                                        }
 
                                }else{
-                                       for (int l = lineStart; l <= lineEnd; l++)              
-                                               update (new TextChange (lines[l].Start, 0, "\t"));                              
+                                       for (int l = lineStart; l <= lineEnd; l++)
+                                               update (new TextChange (lines[l].Start, 0, "\t"));
                                }
-                               
+
                                selectionStart = new CharLocation (lineStart, 0);
                                CurrentLoc = new CharLocation (lineEnd, lines[lineEnd].Length);
 
@@ -288,7 +288,7 @@ namespace Crow
                                return;
                        }
                        base.onKeyDown(sender, e);
-               }               
+               }
 
                protected override void drawContent (Context gr) {
                        try {
@@ -297,7 +297,7 @@ namespace Crow
                                                base.drawContent (gr);
                                                return;
                                        }
-                               
+
                                        Rectangle cb = ClientRectangle;
                                        fe = gr.FontExtents;
                                        double lineHeight = fe.Ascent + fe.Descent;
@@ -359,7 +359,7 @@ namespace Crow
                                        TextExtents extents;
                                        int tokPtr = 0;
                                        Token tok = source.Tokens[tokPtr];
-                                       bool multilineToken = false;                            
+                                       bool multilineToken = false;
 
                                        ReadOnlySpan<char> buff = sourceBytes;
 
@@ -369,7 +369,7 @@ namespace Crow
 
                                                if (multilineToken) {
                                                        if (tok.End < lines[i].End) {//last incomplete line of multiline token
-                                                               buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);                                                            
+                                                               buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);
                                                        } else {//print full line
                                                                buff = sourceBytes.Slice (lines[i].Start, lines[i].Length);
                                                        }
@@ -399,7 +399,7 @@ namespace Crow
                                                                        gr.SetSource(Colors.DarkSlateBlue);
                                                                }else {
                                                                        gr.SetSource(Colors.Red);
-                                                               }                                                                       
+                                                               }
                                                        }
 
                                                        int size = buff.Length * 4 + 1;
@@ -414,7 +414,7 @@ namespace Crow
                                                                gr.MoveTo (pixX, lineHeight * y + fe.Ascent);
                                                                gr.ShowText (bytes.Slice (0, encodedBytes));
                                                                pixX += extents.XAdvance;
-                                                               x += buff.Length;                                                               
+                                                               x += buff.Length;
                                                        }
 
                                                        if (multilineToken) {
@@ -432,7 +432,7 @@ namespace Crow
                                                if (HasFocus && selectionNotEmpty) {
                                                        RectangleD lineRect = new RectangleD (cb.X,     lineHeight * y + cb.Top, pixX, lineHeight);
                                                        RectangleD selRect = lineRect;
-                                                       
+
                                                        if (i >= selStart.Line && i <= selEnd.Line) {
                                                                if (selStart.Line == selEnd.Line) {
                                                                        selRect.X = selStart.VisualCharXPosition + cb.X;
@@ -478,7 +478,7 @@ namespace Crow
 
                                                x = 0;
                                                pixX = 0;
-                       
+
                                                y++;
 
 
@@ -492,13 +492,13 @@ namespace Crow
                                                                        continue;
                                                                } else if (tok2.Type == TokenType.WhiteSpace) {
                                                                        x += tok2.Length;
-                                                                       pixX += spacePixelWidth * tok2.Length;*/                                                                                                                                                                
-                                       }                                       
+                                                                       pixX += spacePixelWidth * tok2.Length;*/
+                                       }
                                        //gr.Translate (ScrollX, ScrollY);
                                }
                        } catch {
-                               
+
                        }
-               }                       
+               }
        }
 }
\ No newline at end of file
index 0622c2cff0060d8d39353195bec047294f34f8d7..b44bb8f5f84b85581fc102f4a0e697707c729b64 100644 (file)
@@ -70,11 +70,18 @@ namespace Samples
                        new ActionCommand("File command three", (sender) => showMsgBox (sender))
                );
                public ActionCommand SingleCommand => new ActionCommand("Single command 1", (sender) => showMsgBox (sender), "#Icons.gavel.svg");
-               public ToggleCommand CMDToggleBoolVal => new ToggleCommand ("Toggle", this, "BoolVal", "#Icons.gavel.svg", true);
-               public ToggleCommand CMDToggleBoolValField => new ToggleCommand ("ToggleField", this, "boolVal", "#Icons.gavel.svg", true);
+               public ToggleCommand CMDToggleBoolVal, CMDToggleBoolValField;
+
+               public ActionCommand CMDHosted;
 
                void initCommands()
                {
+                       CMDToggleBoolVal = new ToggleCommand (this, "Toggle", new Binding<bool> ("BoolVal"), "#Icons.gavel.svg", null, true);
+                       CMDToggleBoolValField = new ToggleCommand (this, "ToggleField", new Binding<bool> ("boolVal"), "#Icons.gavel.svg", null, true);
+                       CMDHosted = new ActionCommand (this, "Hosted command",
+                               () => MessageBox.ShowModal(this, MessageBox.Type.Information, "hosted command triggered"), "#Icons.binding.svg",
+                               new KeyBinding (Key.F1, Modifier.Super),
+                               new Binding<bool> ("CanExecute"));
                        Commands = new CommandGroup("commands msg boxes",
                                new ActionCommand("Action 1", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 1 clicked")),
                                new ActionCommand("Action two", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 2 clicked"), null, false),
@@ -339,7 +346,7 @@ namespace Samples
 
 
                string curSources = "";
-               public bool boolVal = true;
+               public bool boolVal = true, canExecute;
                public string CurSources
                {
                        get => curSources;
@@ -358,7 +365,16 @@ namespace Samples
                                        return;
                                boolVal = value;
                                NotifyValueChanged(boolVal);
-                               Console.WriteLine ($"boolVal => {value}");
+                       }
+               }
+               public bool CanExecute
+               {
+                       get => canExecute;
+                       set     {
+                               if (canExecute == value)
+                                       return;
+                               canExecute = value;
+                               NotifyValueChanged(canExecute);
                        }
                }
                public Color AllWidgetBackground {
@@ -387,10 +403,10 @@ namespace Samples
                        base.processDrawing(ctx);
                }
 
-               public override bool OnKeyDown(Key key)
+               public override bool OnKeyDown(KeyEventArgs e)
                {
 
-                       switch (key)
+                       switch (e.Key)
                        {
                                case Key.F5:
                                        Load("Interfaces/Divers/testFileDialog.crow").DataSource = this;
@@ -407,7 +423,7 @@ namespace Samples
                                        DbgLogger.Save(this);
                                        return true;
                        }
-                       return base.OnKeyDown(key);
+                       return base.OnKeyDown(e);
                }
        }
 }
\ No newline at end of file
index 47b931030387c6823e6352e82e6f26fe21ad82e5..e1cadc0a26d23dae4908879d611611d9c329af64 100644 (file)
@@ -27,11 +27,11 @@ namespace Samples
 
                        if (string.IsNullOrEmpty (CurrentDir))
                                CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces");
-                       
+
                }
 
                protected const string _defaultFileName = "unnamed.txt";
-               protected string source = "", origSource;               
+               protected string source = "", origSource;
                protected TextBox editor;
                bool debugLogRecording;
 
@@ -53,7 +53,7 @@ namespace Samples
                                Configuration.Global.Set (nameof (CurrentFile), value);
                                NotifyValueChanged (CurrentFile);
                        }
-               }               
+               }
                public virtual string Source {
                        get => source;
                        set {
@@ -71,8 +71,8 @@ namespace Samples
                        get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents));
                        set {
                                if (RecordedEvents == value)
-                                       return;                         
-                               Configuration.Global.Set (nameof (RecordedEvents), value);                              
+                                       return;
+                               Configuration.Global.Set (nameof (RecordedEvents), value);
                                if (DebugLogRecording)
                                        DbgLogger.IncludeEvents = RecordedEvents;
                                NotifyValueChanged(RecordedEvents);
@@ -102,7 +102,7 @@ namespace Samples
                        get => Configuration.Global.Get<bool> (nameof(DebugLogToFile));
                        set {
                                if (DebugLogToFile == value)
-                                       return;                         
+                                       return;
                                Configuration.Global.Set (nameof(DebugLogToFile), value);
                                NotifyValueChanged(DebugLogToFile);
                                DbgLogger.ConsoleOutput = !value;
@@ -134,7 +134,7 @@ namespace Samples
                public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs);
                protected virtual void initCommands ()
                {
-                       CMDNew  = new ActionCommand ("New", new Action (onNewFile), "#Icons.blank-file.svg");                   
+                       CMDNew  = new ActionCommand ("New", new Action (onNewFile), "#Icons.blank-file.svg");
                        CMDSave = new ActionCommand ("Save", new Action (onSave), "#Icons.save.svg", false);
                        CMDSaveAs = new ActionCommand ("Save As...", new Action (onSaveAs), "#Icons.save.svg");
                        CMDQuit = new ActionCommand ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg");
@@ -149,7 +149,7 @@ namespace Samples
                protected Stack<TextChange> undoStack = new Stack<TextChange> ();
                protected Stack<TextChange> redoStack = new Stack<TextChange> ();
                protected TextSpan selection;
-               protected string SelectedText =>        
+               protected string SelectedText =>
                                selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString ();
 
                protected void undo () {
@@ -176,7 +176,7 @@ namespace Samples
                        undoStack.Clear ();
                        redoStack.Clear ();
                        CMDUndo.CanExecute = false;
-                       CMDRedo.CanExecute = false;                     
+                       CMDRedo.CanExecute = false;
                }
 
                protected void cut () {
@@ -186,11 +186,11 @@ namespace Samples
                protected void copy () {
                        Clipboard = SelectedText;
                }
-               protected void paste () {                       
+               protected void paste () {
                        applyChange (new TextChange (selection.Start, selection.Length, Clipboard));
                }
                protected void onNewFile () {
-                       if (IsDirty) {                          
+                       if (IsDirty) {
                                MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?").Yes += (sender, e) => newFile ();
                        } else
                                newFile ();
@@ -257,7 +257,7 @@ namespace Samples
                        CMDSave.CanExecute = false;
                }
 
-               protected void reloadFromFile () {                      
+               protected void reloadFromFile () {
                        disableTextChangedEvent = true;
                        if (File.Exists (CurrentFile)) {
                                using (Stream s = new FileStream (CurrentFile, FileMode.Open)) {
@@ -267,7 +267,7 @@ namespace Samples
                        }
                        disableTextChangedEvent = false;
                        resetUndoRedo ();
-               }               
+               }
                protected bool disableTextChangedEvent = false;
                protected void apply (TextChange change) {
                        Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)];
@@ -278,8 +278,8 @@ namespace Samples
                        src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
                        disableTextChangedEvent = true;
                        Source = tmp.ToString ();
-                       disableTextChangedEvent = false;                        
-               }       
+                       disableTextChangedEvent = false;
+               }
                protected void applyChange (TextChange change) {
                        undoStack.Push (change.Inverse (source));
                        redoStack.Clear ();
@@ -319,8 +319,8 @@ namespace Samples
                                return;
                        applyChange (e.Change);
                }
-               
-               protected void onSelectedTextChanged (object sender, EventArgs e) {                     
+
+               protected void onSelectedTextChanged (object sender, EventArgs e) {
                        selection = (sender as Label).Selection;
                        Console.WriteLine($"selection:{selection.Start} length:{selection.Length}");
                        CMDCut.CanExecute = CMDCopy.CanExecute = !selection.IsEmpty;
diff --git a/Samples/common/ui/Interfaces/Experimental/hostedCommand.crow b/Samples/common/ui/Interfaces/Experimental/hostedCommand.crow
new file mode 100644 (file)
index 0000000..444fbe2
--- /dev/null
@@ -0,0 +1,13 @@
+<VerticalStack Fit="true">
+       <CheckBox Caption="Can execute ?" IsChecked="{²CanExecute}"/>
+       <Button Command="{CMDHosted}" Foreground="White" Background="Jet">
+               <Template>
+<Border Style="ButtonBorder" Background="{./Background}" Name="Content" CornerRadius="{../CornerRadius}" >
+       <HorizontalStack DataSource="{./Command}">
+               <Label Font="Arial, 14" Name="caption" Margin="${ButtonCaptionMargin}" Foreground="{./Foreground}" Text="{./Caption}"/>
+               <Label Font="Condensed, 9" Text="{KeyBinding}" Foreground="Grey"/>
+       </HorizontalStack>
+</Border>
+               </Template>
+       </Button>
+</VerticalStack>
\ No newline at end of file
index 29dcf7e0117f918cc268331881a8774a82c512b8..40a39abb4e6c11fe91ac38df13f5ee00784f6b2d 100644 (file)
@@ -1,7 +1,7 @@
 <VerticalStack Fit="true">
        <HorizontalStack Fit="true">
                <Button Command="{CMDToggleBoolVal}"/>
-               <CheckBox IsChecked="{²BoolVal}"/>
+               <CheckBox Caption="direct bound to bool value" IsChecked="{²BoolVal}" Background="Jet"/>
                <Button Command="{CMDToggleBoolVal}">
                        <Template>
                                <Container DataSource="{./Command}">