<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>
<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>-->
</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>
{
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
}
}
}
+ 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;
+ }
+ }
}
--- /dev/null
+// 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
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,
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
}
}
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>();
public CommandGroup (params CommandBase[] commands) {
Commands = new ObservableList<CommandBase>(commands);
}
+ public CommandGroup (ICommandHost host) {
+
+ }
public int Count => Commands.Count;
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;
--- /dev/null
+// 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
/// <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)
ToggleOff.Raise (this, null);
}
- #endregion
- object instance;
- string memberName;
- Action<bool> delSet;
- Func<bool> delGet;
- bool disposedValue;
/// <summary>
}
#region IToggle implementation
-
public event EventHandler ToggleOn;
public event EventHandler ToggleOff;
public BooleanTestOnInstance IsToggleable {get; set; }
}
#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
}
}
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
Layouting,
Drawing
}
- public static PerformanceMeasure[] Measures;
+ public static PerformanceMeasure[] Measures;
[Conditional("MEASURE_TIME")]
public static void InitMeasures () {
[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) {
}
}
- void computeStats(){
+ void computeStats(){
current = timer.ElapsedMilliseconds;
if (current < cancelLimit)
return;
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);
Vertical
}
- public enum Alignment
+ public enum Alignment
{
Top = 0x01,
Left = 0x02,
ur_angle,
watch,
X_cursor,
- xterm,
+ xterm,
}
/// <summary>
/// Cursor shape use in Sliders
public class ListClearEventArg : EventArgs
{
public IEnumerable<object> Elements;
- public ListClearEventArg (IEnumerable<object> elements) {
+ public ListClearEventArg (IEnumerable<object> elements) {
Elements = elements;
}
}
public double Offset;
public Color Color;
- public ColorStop(double offset, Color color){
+ public ColorStop(double offset, Color color){
Offset = offset;
Color = color;
}
{
if (string.IsNullOrEmpty (s))
return null;
-
+
string[] parts = s.Trim ().Split (':');
if (parts.Length > 2)
continue;
grad.AddColorStop (cs.Offset, cs.Color);
}
-
+
ctx.SetSource (grad);
grad.Dispose ();
}
eiEvt.RemoveEventHandler (instance, d);
#if DEBUG_BINDING
Console.WriteLine ("\tremoveEventHandlerByName: {0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+
#endif
}
}
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;
+ }
}
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;
}
}
- public class MouseButtonEventArgs : MouseEventArgs
+ public class MouseButtonEventArgs : MouseEventArgs
{
public readonly MouseButton Button;
public readonly InputAction Action;
/// 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;
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) => {
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;*/
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) {
").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;
}
NotifyValueChanged (mName, e.NewValue);
}
- protected override void Dispose(bool disposing)
- {
- if (command is IDisposable dis)
- dis.Dispose ();
- base.Dispose(disposing);
- }
}
}
public event EventHandler<TextChangeEventArgs> TextChanged;
public virtual void OnTextChanged(Object sender, TextChangeEventArgs e)
- {
+ {
TextChanged.Raise (this, e);
}
//TODO:change protected to private
#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;
/// <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; }
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.
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;
} 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);
}
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--;
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) {
}
}
}
-
- protected void getLines () {
+
+ protected void getLines () {
if (lines == null)
lines = new LineCollection (_multiline ? 4 : 1);
else
}
if (!CurrentLoc.Value.HasVisualX) {
setFontForContext (ctx);
- lock (linesMutex) {
+ lock (linesMutex) {
if (currentLoc?.Column < 0) {
updateLocation (ctx, ClientRectangle.Width, ref currentLoc);
NotifyValueChanged ("CurrentColumn", CurrentColumn);
//}
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);
return false;
}
try {
- bool result = base.UpdateLayout (layoutType);
+ bool result = base.UpdateLayout (layoutType);
return result;
} finally {
System.Threading.Monitor.Exit (linesMutex);
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);
base.onDraw (gr);
setFontForContext (gr);
-
+
if (!textMeasureIsUpToDate) {
lock (linesMutex)
measureTextBounds (gr);
}
-
+
if (ClipToClientRect) {
gr.Save ();
CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
lock (linesMutex)
drawContent (gr);
-
+
if (ClipToClientRect)
gr.Restore ();
{
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 ();
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)
{
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;
IFace.forceTextCursor = true;
RegisterForRedraw ();
e.Handled = true;
- }
+ }
}
base.onMouseDown (sender, e);
{
base.onMouseUp (sender, e);
if (e.Button != MouseButton.Left || !HasFocus || !selectionStart.HasValue)
- return;
+ return;
if (selectionStart.Value == CurrentLoc.Value)
selectionStart = null;
}
return;
GotoWordStart ();
- selectionStart = CurrentLoc;
+ selectionStart = CurrentLoc;
GotoWordEnd ();
RegisterForRedraw ();
}
#region Keyboard handling
public override void onKeyDown (object sender, KeyEventArgs e) {
-
+
switch (e.Key) {
case Key.Escape:
selectionStart = null;
return;
}
IFace.forceTextCursor = true;
- e.Handled = true;
+ e.Handled = true;
}
#endregion
tmp = tmp.LogicalParent as MenuItem;
}
}
- protected override void Dispose(bool disposing)
- {
- if (command is IDisposable dis)
- dis.Dispose ();
- base.Dispose(disposing);
- }
}
}
return true;
if (child == null)
return false;
- return child.FindByDesignID (designID, out go);
+ return child.FindByDesignID (designID, out go);
}
#endif
protected Widget child;
if (child != null) {
child.Parent = this;
child.LayoutChanged += OnChildLayoutChanges;
- contentSize = child.Slot.Size;
+ contentSize = child.Slot.Size;
child.RegisterForLayouting (LayoutingType.Sizing);
}
}
}
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)
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 {
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;
gr.Rectangle(Clipping.GetRectangle(i));
gr.ClipPreserve();
gr.Operator = Operator.Clear;
- gr.Fill();
+ gr.Fill();
gr.Operator = Operator.Over;
onDraw (gr);
{
base.checkHoverWidget (e);
- if (child != null)
- if (child.MouseIsIn (e.Position))
+ if (child != null)
+ if (child.MouseIsIn (e.Position))
child.checkHoverWidget (e);
}
#endregion
}
/// <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;
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;
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) {
TextSpan selection = Selection;
if (selection.IsEmpty)
return;
- IFace.Clipboard = SelectedText;
+ IFace.Clipboard = SelectedText;
}
public virtual void Paste () {
TextSpan selection = Selection;
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 {
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);
NotifyValueChanged ("Text", Text);
OnTextChanged (this, new TextChangeEventArgs (change));
-
+
RegisterForGraphicUpdate ();
}
protected override string LogName => "tb";
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
}
- 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;
}
return true;
}
- return base.OnKeyDown (key);
+ return base.OnKeyDown (e);
}
}
}
\ No newline at end of file
<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"
XmlSource source;
object TokenMutex = new object();
- void parse () {
+ void parse () {
XmlSource tmp = new XmlSource(_text);
lock(TokenMutex)
source = tmp;
if (suggestions == null || suggestions.Count == 0)
hideOverlay ();
else
- showOverlay ();
+ showOverlay ();
}
}
bool suggestionsActive => overlay != null && overlay.IsVisible;
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)
{
//Task.Run(()=>parse());
parse();
-
+
if (!disableSuggestions && HasFocus)
tryGetSuggestions ();
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}");
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 ();
}
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"});
}
}
}
- }
- } 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))
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 () {
return;
overlay.IsVisible = false;
}
- void completeToken () {
+ void completeToken () {
string selectedSugg = overlay.SelectedItem is MemberInfo mi ?
mi.Name : overlay.SelectedItem?.ToString ();
if (selectedSugg == null)
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 ();
}
hideOverlay ();
base.onMouseDown (sender, e);
}
-
+
public override void onKeyDown(object sender, KeyEventArgs e)
{
TextSpan selection = Selection;
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])) {
}
}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);
return;
}
base.onKeyDown(sender, e);
- }
+ }
protected override void drawContent (Context gr) {
try {
base.drawContent (gr);
return;
}
-
+
Rectangle cb = ClientRectangle;
fe = gr.FontExtents;
double lineHeight = fe.Ascent + fe.Descent;
TextExtents extents;
int tokPtr = 0;
Token tok = source.Tokens[tokPtr];
- bool multilineToken = false;
+ bool multilineToken = false;
ReadOnlySpan<char> buff = sourceBytes;
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);
}
gr.SetSource(Colors.DarkSlateBlue);
}else {
gr.SetSource(Colors.Red);
- }
+ }
}
int size = buff.Length * 4 + 1;
gr.MoveTo (pixX, lineHeight * y + fe.Ascent);
gr.ShowText (bytes.Slice (0, encodedBytes));
pixX += extents.XAdvance;
- x += buff.Length;
+ x += buff.Length;
}
if (multilineToken) {
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;
x = 0;
pixX = 0;
-
+
y++;
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
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),
string curSources = "";
- public bool boolVal = true;
+ public bool boolVal = true, canExecute;
public string CurSources
{
get => curSources;
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 {
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;
DbgLogger.Save(this);
return true;
}
- return base.OnKeyDown(key);
+ return base.OnKeyDown(e);
}
}
}
\ No newline at end of file
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;
Configuration.Global.Set (nameof (CurrentFile), value);
NotifyValueChanged (CurrentFile);
}
- }
+ }
public virtual string Source {
get => source;
set {
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);
get => Configuration.Global.Get<bool> (nameof(DebugLogToFile));
set {
if (DebugLogToFile == value)
- return;
+ return;
Configuration.Global.Set (nameof(DebugLogToFile), value);
NotifyValueChanged(DebugLogToFile);
DbgLogger.ConsoleOutput = !value;
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");
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 () {
undoStack.Clear ();
redoStack.Clear ();
CMDUndo.CanExecute = false;
- CMDRedo.CanExecute = false;
+ CMDRedo.CanExecute = false;
}
protected void cut () {
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 ();
CMDSave.CanExecute = false;
}
- protected void reloadFromFile () {
+ protected void reloadFromFile () {
disableTextChangedEvent = true;
if (File.Exists (CurrentFile)) {
using (Stream s = new FileStream (CurrentFile, FileMode.Open)) {
}
disableTextChangedEvent = false;
resetUndoRedo ();
- }
+ }
protected bool disableTextChangedEvent = false;
protected void apply (TextChange change) {
Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)];
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 ();
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;
--- /dev/null
+<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
<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}">