From: Jean-Philippe Bruyère Date: Wed, 15 Sep 2021 19:26:39 +0000 (+0000) Subject: hosted command X-Git-Tag: v0.9.7-beta~9 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=8b343e10f1a65b07988e15ea76596b16a03adadc;p=jp%2Fcrow.git hosted command --- diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index 3b054bb4..1c61b00e 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -3,10 +3,10 @@ netstandard2.1 - + $(CrowVersion) $(CrowPackageVersion) - + C# Rapid Open Widget Toolkit C.R.O.W. is a widget toolkit and rendering engine developed in C# with templates, styles, compositing, and bindings. MIT @@ -23,7 +23,7 @@ True true $(NoWarn);1591;1587;1570;1572;1573;1574 - MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS + MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS false false @@ -40,7 +40,7 @@ - + diff --git a/Crow/src/Command/ActionCommand.cs b/Crow/src/Command/ActionCommand.cs index 02bec998..f484e0ed 100644 --- a/Crow/src/Command/ActionCommand.cs +++ b/Crow/src/Command/ActionCommand.cs @@ -39,9 +39,22 @@ namespace Crow { { execute = executeAction; } + public ActionCommand (ICommandHost _host, string caption, Action executeAction, string icon = null, KeyBinding _keyBinding = null, + Binding _canExecuteBinding = null) + : base (_host, caption, icon, _keyBinding, _canExecuteBinding) + { + execute = executeAction; + } + public ActionCommand (ICommandHost _host, string caption, Action executeAction, string icon = null, KeyBinding _keyBinding = null, + Binding _canExecuteBinding = null) + : base (_host, caption, icon, _keyBinding, _canExecuteBinding) + { + execute = executeAction; + } + #endregion - Delegate execute; + protected Delegate execute; /// /// trigger the execution of the command @@ -56,4 +69,14 @@ namespace Crow { } } } + public class ActionCommand : ActionCommand { + public ActionCommand (Action _executeAction) { + execute = _executeAction; + } + public ActionCommand (string caption, Action 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 index 00000000..4437e98e --- /dev/null +++ b/Crow/src/Command/Binding.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2021-2021 Jean-Philippe Bruyère +// +// 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 { + public string SourceMember; + public Func FetchFunc; + + public Binding (string memberName, Func 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: {mbi.MemberType}"); + } + public Func CreateGetter (object instance) { + MemberInfo mbi = instance.GetType().GetMember (SourceMember, BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(); + if (mbi is PropertyInfo pi) { + return (Func)Delegate.CreateDelegate (typeof (Func), 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)dm.CreateDelegate (typeof (Func), instance); + } else + throw new Exception ("unsupported member type for Binding.CreateGetter"); + } + public Action CreateSetter (object instance) { + MemberInfo mbi = instance.GetType().GetMember (SourceMember, BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(); + if (mbi is PropertyInfo pi) { + return (Action)Delegate.CreateDelegate (typeof (Action), 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)dm.CreateDelegate (typeof (Action), instance); + } else + throw new Exception ("unsupported member type for Binding CreateSetter"); + } + } +} \ No newline at end of file diff --git a/Crow/src/Command/Command.cs b/Crow/src/Command/Command.cs index f44fe5b3..85c44413 100644 --- a/Crow/src/Command/Command.cs +++ b/Crow/src/Command/Command.cs @@ -7,20 +7,56 @@ using System.ComponentModel; using System.Threading.Tasks; namespace Crow { + + public interface ICommandHost : IValueChange + { + event EventHandler KeyDown; + } /// /// Base abstract class for commands with an execute method. /// - 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 _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 canExecuteBinding; + + public KeyBinding KeyBinding => keyBinding; + public bool HasKeyBinding => keyBinding != null; + public bool HasCanExecuteBinding => canExecuteBinding != null; /// /// 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 } } diff --git a/Crow/src/Command/CommandGroup.cs b/Crow/src/Command/CommandGroup.cs index d323ae85..6c5a76ba 100644 --- a/Crow/src/Command/CommandGroup.cs +++ b/Crow/src/Command/CommandGroup.cs @@ -9,7 +9,8 @@ using System.Linq; namespace Crow { public class CommandGroup : CommandBase, IEnumerable, IList { - public IList Commands; + public IList Commands { get; private set; } + public CommandGroup () { Commands = new ObservableList(); @@ -25,6 +26,9 @@ namespace Crow { public CommandGroup (params CommandBase[] commands) { Commands = new ObservableList(commands); } + public CommandGroup (ICommandHost host) { + + } public int Count => Commands.Count; @@ -61,7 +65,10 @@ namespace Crow { foreach (CommandBase c in items) Commands.Remove (c); } - /// + /// + /// Set boolean value for the CanExecute state of all commands + /// + /// public void ToggleAllCommand (bool canExecute) { foreach (ActionCommand c in Commands.OfType ()) c.CanExecute = canExecute; diff --git a/Crow/src/Command/KeyBinding.cs b/Crow/src/Command/KeyBinding.cs new file mode 100644 index 00000000..2c854048 --- /dev/null +++ b/Crow/src/Command/KeyBinding.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2021-2021 Jean-Philippe Bruyère +// +// 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 (tmp[0], out Key k)) { + if (tmp.Length > 1 && FlagEnums.TryParseFlags (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 diff --git a/Crow/src/Command/ToggleCommand.cs b/Crow/src/Command/ToggleCommand.cs index 6182195c..45032a22 100644 --- a/Crow/src/Command/ToggleCommand.cs +++ b/Crow/src/Command/ToggleCommand.cs @@ -13,54 +13,33 @@ namespace Crow { /// /// helper class to bind in one step icon, caption, action, and validity tests to a controls /// - 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 toggleBinding, string icon = null, KeyBinding _keyBinding = null, + Binding _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)Delegate.CreateDelegate (typeof (Action), instance, pi.GetSetMethod ()); - delGet = (Func)Delegate.CreateDelegate (typeof (Func), 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)dm.CreateDelegate (typeof (Action), 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)dm.CreateDelegate (typeof (Func), 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 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 binding; + Action delSet; + Func 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 delSet; - Func delGet; - bool disposedValue; /// @@ -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 } } diff --git a/Crow/src/DebugUtils/PerformanceMeasure.cs b/Crow/src/DebugUtils/PerformanceMeasure.cs index 8cd72d97..6fa2ad2d 100644 --- a/Crow/src/DebugUtils/PerformanceMeasure.cs +++ b/Crow/src/DebugUtils/PerformanceMeasure.cs @@ -12,7 +12,7 @@ namespace Crow public event EventHandler 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); diff --git a/Crow/src/Enums.cs b/Crow/src/Enums.cs index ebbb8d22..866e32a9 100644 --- a/Crow/src/Enums.cs +++ b/Crow/src/Enums.cs @@ -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, } /// /// Cursor shape use in Sliders diff --git a/Crow/src/EventArgs/ListChangedEventArg.cs b/Crow/src/EventArgs/ListChangedEventArg.cs index 2d8553b8..7f83cfaf 100644 --- a/Crow/src/EventArgs/ListChangedEventArg.cs +++ b/Crow/src/EventArgs/ListChangedEventArg.cs @@ -19,7 +19,7 @@ namespace Crow public class ListClearEventArg : EventArgs { public IEnumerable Elements; - public ListClearEventArg (IEnumerable elements) { + public ListClearEventArg (IEnumerable elements) { Elements = elements; } } diff --git a/Crow/src/Fill/Gradient.cs b/Crow/src/Fill/Gradient.cs index 7fe3d4c1..2d344c73 100644 --- a/Crow/src/Fill/Gradient.cs +++ b/Crow/src/Fill/Gradient.cs @@ -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 (); } diff --git a/Crow/src/IML/CompilerServices.cs b/Crow/src/IML/CompilerServices.cs index 3daf82ab..69c74e42 100644 --- a/Crow/src/IML/CompilerServices.cs +++ b/Crow/src/IML/CompilerServices.cs @@ -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 } } diff --git a/Crow/src/Input/KeyEventArgs.cs b/Crow/src/Input/KeyEventArgs.cs index 23f8559d..30605e78 100644 --- a/Crow/src/Input/KeyEventArgs.cs +++ b/Crow/src/Input/KeyEventArgs.cs @@ -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; + } } diff --git a/Crow/src/Input/MouseEventArgs.cs b/Crow/src/Input/MouseEventArgs.cs index 9d3badda..f84822eb 100644 --- a/Crow/src/Input/MouseEventArgs.cs +++ b/Crow/src/Input/MouseEventArgs.cs @@ -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; diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index b46bf018..ede2927e 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -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. /// - public class Interface : ILayoutable, IDisposable, IValueChange + public class Interface : ILayoutable, IDisposable, ICommandHost { #region IValueChange implementation public event EventHandler 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 (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 KeyDown; + public event EventHandler KeyUp; + //public event EventHandler MouseWheelChanged; //public event EventHandler MouseButtonUp; //public event EventHandler MouseButtonDown; //public event EventHandler MouseClick; //public event EventHandler MouseMove; //public event EventHandler KeyDown; - //public event EventHandler KeyUp; //public event EventHandler KeyPress; /*public event EventHandler KeyboardKeyDown; public event EventHandler 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; diff --git a/Crow/src/Widgets/Button.cs b/Crow/src/Widgets/Button.cs index 6c005629..a6b57687 100644 --- a/Crow/src/Widgets/Button.cs +++ b/Crow/src/Widgets/Button.cs @@ -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); - } } } diff --git a/Crow/src/Widgets/Label.cs b/Crow/src/Widgets/Label.cs index e01fe269..9a16bf87 100644 --- a/Crow/src/Widgets/Label.cs +++ b/Crow/src/Widgets/Label.cs @@ -28,7 +28,7 @@ namespace Crow public event EventHandler 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 /// /// If measure is not 'Fit', align text inside the bounds of this label. /// - [DefaultValue(TextAlignment.Left)] + [DefaultValue(TextAlignment.Left)] public TextAlignment TextAlignment { get { return _textAlignment; } @@ -142,7 +142,7 @@ namespace Crow RegisterForRedraw (); NotifyValueChangedAuto (_textAlignment); } - } + } /// /// 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(); } } - + /// /// Moves cursor one char to the left. /// - /// true if move succeed + /// true if move succeed 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 diff --git a/Crow/src/Widgets/MenuItem.cs b/Crow/src/Widgets/MenuItem.cs index c861441f..e9160095 100644 --- a/Crow/src/Widgets/MenuItem.cs +++ b/Crow/src/Widgets/MenuItem.cs @@ -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); - } } } diff --git a/Crow/src/Widgets/PrivateContainer.cs b/Crow/src/Widgets/PrivateContainer.cs index b08e1857..b5e9fbc2 100644 --- a/Crow/src/Widgets/PrivateContainer.cs +++ b/Crow/src/Widgets/PrivateContainer.cs @@ -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 diff --git a/Crow/src/Widgets/TextBox.cs b/Crow/src/Widgets/TextBox.cs index aebcc071..12d6ce1e 100644 --- a/Crow/src/Widgets/TextBox.cs +++ b/Crow/src/Widgets/TextBox.cs @@ -134,7 +134,7 @@ namespace Crow } /// Process scrolling vertically, or if shift is down, vertically - 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"; diff --git a/Crow/src/Widgets/Widget.cs b/Crow/src/Widgets/Widget.cs index 4dbcb340..0b5b4463 100644 --- a/Crow/src/Widgets/Widget.cs +++ b/Crow/src/Widgets/Widget.cs @@ -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 diff --git a/Samples/ShowCase/ShowCase.cs b/Samples/ShowCase/ShowCase.cs index 5aa36fa7..cb094e4a 100644 --- a/Samples/ShowCase/ShowCase.cs +++ b/Samples/ShowCase/ShowCase.cs @@ -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 diff --git a/Samples/ShowCase/ui/showcase.crow b/Samples/ShowCase/ui/showcase.crow index de32059e..c64fa740 100644 --- a/Samples/ShowCase/ui/showcase.crow +++ b/Samples/ShowCase/ui/showcase.crow @@ -25,7 +25,7 @@ - +