using System.ComponentModel;
using System.Threading.Tasks;
-namespace Crow {
+namespace Crow {
/// <summary>
- /// helper class to bind in one step icon, caption, action, and validity tests to a controls
+ /// helper class to bind in one step icon, caption, action, and validity tests to a controls
/// </summary>
public class Command : CommandBase
{
#region CTOR
public Command () {}
+ public Command (string caption, string icon = null, bool _canExecute = true)
+ :base (caption, icon)
+ {}
+
/// <summary>
/// Initializes a new instance of Command with the action passed as argument.
/// </summary>
}
public Command (string caption, Action executeAction, string icon = null, bool _canExecute = true)
:base (caption, icon)
- {
+ {
execute = executeAction;
canExecute = _canExecute;
}
public Command (string caption, Action<object> executeAction, string icon = null, bool _canExecute = true)
:base (caption, icon)
- {
+ {
execute = executeAction;
canExecute = _canExecute;
}
-
+
#endregion
- Delegate execute;
+ Delegate execute;
bool canExecute = true;
-
+
/// <summary>
/// if true, action defined in this command may be executed,
/// </summary>
canExecute = value;
NotifyValueChanged ("CanExecute", canExecute);
}
- }
+ }
/// <summary>
/// trigger the execution of the command
public virtual void Execute (object sender = null){
if (execute != null && CanExecute){
Task task = (execute is Action a) ?
- task = new Task(a) :
+ task = new Task(a) :
(execute is Action<object> o) ?
task = new Task(o, sender) : throw new Exception("Invalid Delegate type in Crow.Command, expecting Action or Action<object>");
task.Start();
ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value));
}
#endregion
-
+
#region CTOR
protected CommandBase() {}
protected CommandBase (string _caption, string _icon = null)
{
- caption = _caption;
+ caption = _caption;
icon = _icon;
}
#endregion
-
+
string caption, icon;
/// <summary>
}
/// <summary>
/// Icon to display in the bound control
- /// </summary>
+ /// </summary>
public string Icon {
get => icon;
set {
NotifyValueChanged ("Icon", icon);
}
}
- internal virtual void raiseAllValuesChanged() {
+ internal virtual void raiseAllValuesChanged() {
NotifyValueChanged ("Icon", icon);
NotifyValueChanged ("Caption", caption);
}
using System.Collections;
using System.Collections.Generic;
+using System.Linq;
namespace Crow {
public class CommandGroup : CommandBase, IEnumerable, IList<CommandBase>
Commands = new ObservableList<CommandBase>(commands);
}
-
+
public int Count => Commands.Count;
public bool IsReadOnly => false;
public bool Contains(CommandBase item) => Commands.Contains (item);
- public void CopyTo(CommandBase[] array, int arrayIndex) => Commands.CopyTo (array, arrayIndex);
+ public void CopyTo(CommandBase[] array, int arrayIndex) => Commands.CopyTo (array, arrayIndex);
public bool Remove(CommandBase item) => Commands.Remove (item);
IEnumerator<CommandBase> IEnumerable<CommandBase>.GetEnumerator()
=> Commands.GetEnumerator();
+ public void Add (params CommandBase[] items) {
+ foreach (CommandBase c in items)
+ Commands.Add (c);
+ }
+ public void Remove (params CommandBase[] items) {
+ foreach (CommandBase c in items)
+ Commands.Remove (c);
+ }
+ ///
+ public void ToggleAllCommand (bool canExecute) {
+ foreach (Command c in Commands.OfType<Command> ())
+ c.CanExecute = canExecute;
+ }
}
}
--- /dev/null
+// Copyright (c) 2013-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.ComponentModel;
+using System.Reflection;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Reflection.Emit;
+
+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
+ {
+ object instance;
+ string memberName;
+ Action<bool> delSet;
+ Func<bool> delGet;
+
+ #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)
+ {
+ 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;
+
+ CanExecute = _canExecute;
+ }
+ void instance_valueChanged (object sender, ValueChangeEventArgs e) {
+ if (e.MemberName != memberName)
+ return;
+ Console.WriteLine ($"ToggleCommand valueChanged triggered => {e.NewValue}");
+
+ bool tog = (bool)e.NewValue;
+ NotifyValueChanged ("IsToggled", tog);
+ if (tog)
+ ToggleOn.Raise (this, null);
+ else
+ ToggleOff.Raise (this, null);
+
+ }
+ #endregion
+
+ /// <summary>
+ /// trigger the execution of the command
+ /// </summary>
+ public override void Execute (object sender = null){
+ if (CanExecute)
+ IsToggled = !IsToggled;
+ }
+
+ internal override void raiseAllValuesChanged()
+ {
+ base.raiseAllValuesChanged();
+ NotifyValueChanged ("IsToggled", IsToggled);
+ }
+
+ #region IToggle implementation
+
+ public event EventHandler ToggleOn;
+ public event EventHandler ToggleOff;
+ public BooleanTestOnInstance IsToggleable {get; set; }
+ public bool IsToggled {
+ get => delGet ();
+ set {
+ if (value == IsToggled)
+ return;
+ delSet (value);
+ NotifyValueChanged ("IsToggled", IsToggled);
+ Console.WriteLine ($"ToggleCommand.IsToggled => {value}");
+
+ if (IsToggled)
+ ToggleOn.Raise (this, null);
+ else
+ ToggleOff.Raise (this, null);
+ }
+ }
+ #endregion
+
+ bool disposedValue;
+ protected virtual 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);
+ }
+ }
+}
}
public static void DrawCote(this Context ctx, PointD p1, PointD p2,
double stroke = 1.0, bool fill = false, double arrowWidth = 3.0, double arrowLength = 7.0)
- {
+ {
PointD vDir = p2.Substract(p1);
vDir = vDir.GetNormalized ();
PointD vPerp = vDir.GetPerp ();
ctx.LineTo (pA0.Substract (vA));
else
ctx.MoveTo (pA0.Substract (vA));
-
+
ctx.LineTo (p1);
ctx.MoveTo (p2);
}
public static void DrawCoteInverse(this Context ctx, PointD p1, PointD p2,
double stroke = 1.0, bool fill = false, double arrowWidth = 3.0, double arrowLength = 7.0)
- {
+ {
PointD vDir = p2.Substract(p1);
vDir = vDir.GetNormalized ();
PointD vPerp = vDir.GetPerp ();
}
public static void DrawCoteFixed(this Context ctx, PointD p1, PointD p2,
double stroke = 1.0, double coteWidth = 3.0)
- {
+ {
PointD vDir = p2.Substract(p1);
vDir = vDir.GetNormalized ();
PointD vPerp = vDir.GetPerp ();
case Alignment.BottomLeft:
return Alignment.TopRight;
case Alignment.BottomRight:
- return Alignment.TopLeft;
+ return Alignment.TopLeft;
}
return Alignment.Center;
}
return c == '\t' || c.IsAnyLineBreakCharacter() || char.IsWhiteSpace (c);
}
public static object GetDefaultValue(this object obj)
- {
+ {
Type t = obj.GetType ();
if (t.IsValueType)
return Activator.CreateInstance (t);
-
+
return null;
}
}
}
- internal static bool IsAnyLineBreakCharacter (this char c)
+ internal static bool IsAnyLineBreakCharacter (this char c)
=> c == '\n' || c == '\r' || c == '\u0085' || c == '\u2028' || c == '\u2029';
public static bool TryGetResource (this Assembly a, string resId, out Stream stream) {
}
NotifyValueChanged (mName, e.NewValue);
}
-
+ protected override void Dispose(bool disposing)
+ {
+ if (command is IDisposable dis)
+ dis.Dispose ();
+ base.Dispose(disposing);
+ }
}
}
bool isExp = IsExpandable;
NotifyValueChanged ("IsExpandable", isExp);
if (!isExp)
- _isExpanded = false;
+ _isExpanded = false;
NotifyValueChangedAuto (_isExpanded);
NotifyValueChanged ("IsToggled",_isExpanded);
#endregion
public override void AddItem (Widget g)
- {
+ {
base.AddItem (g);
if (orientation == Orientation.Horizontal)
NotifyValueChangedAuto (command);
}
}
-
+
public override bool IsEnabled {
get => Command == null ? base.IsEnabled : Command.CanExecute;
set => base.IsEnabled = value;
}
-
+
public override string Caption {
get => Command == null ? base.Caption : Command.Caption;
set => base.Caption = value;
}
-
+
public string Icon {
get => Command == null ? icon : Command.Icon;
set {
protected virtual void onOpen (object sender, EventArgs e){
Open.Raise (this, null);
}
- protected virtual void onClose (object sender, EventArgs e){
+ protected virtual void onClose (object sender, EventArgs e){
Close.Raise (this, null);
}
public override bool MouseIsIn (Point m)
=> IsEnabled && !IsDragged ? base.MouseIsIn (m) || child.MouseIsIn (m) : false;
-
+
public override void onMouseEnter (object sender, MouseMoveEventArgs e)
{
base.onMouseEnter (sender, e);
if (hasClick)
base.onMouseClick (sender, e);
- if (!IsOpened)
+ if (!IsOpened)
if (LogicalParent is Menu m)
m.AutomaticOpening = false;
-
+
}
void closeMenu () {
MenuItem tmp = LogicalParent as MenuItem;
tmp = tmp.LogicalParent as MenuItem;
}
}
+ protected override void Dispose(bool disposing)
+ {
+ if (command is IDisposable dis)
+ dis.Dispose ();
+ base.Dispose(disposing);
+ }
}
}
LastSlots = default;
LastPaintedSlot = default;*/
//Slot = LastSlots = LastPaintedSlot = default;
- Slot = LastPaintedSlot = default;
+ //Slot = LastPaintedSlot = default;
}
}
}
<Authors>Jean-Philippe Bruyère</Authors>
<LangVersion>7.3</LangVersion>
- <CrowVersion>0.9.6</CrowVersion>
+ <CrowVersion>0.9.7</CrowVersion>
<CrowPackageVersion>$(CrowVersion)-beta</CrowPackageVersion>
<!-- If you dont have a native libstb on your system, enable the managed version of stb here
new Command("File command three", (sender) => showMsgBox (sender))
);
public Command SingleCommand => new Command("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);
void initCommands()
{
NotifyValueChanged(testString);
}
- }
+ }
string prop1;
public string TestList3SelProp1
{
string curSources = "";
- bool boolVal = true;
+ public bool boolVal = true;
public string CurSources
{
get => curSources;
return;
boolVal = value;
NotifyValueChanged(boolVal);
+ Console.WriteLine ($"boolVal => {value}");
}
}
public Color AllWidgetBackground {
--- /dev/null
+<VerticalStack Fit="true">
+ <HorizontalStack Fit="true">
+ <Button Command="{CMDToggleBoolVal}"/>
+ <CheckBox IsChecked="{²BoolVal}"/>
+ <Button Command="{CMDToggleBoolVal}">
+ <Template>
+ <Container DataSource="{./Command}">
+ <CheckBox Caption="{./Caption}" Style="CheckBox2" IsChecked="{²IsToggled}"/>
+ </Container>
+ </Template>
+ </Button>
+ <Button Command="{CMDToggleBoolVal}">
+ <Template>
+ <Border DataSource="{./Command}" Name="Content" Margin="2"
+ Background="DarkGrey" Tooltip="{./Caption}"
+ Foreground="Transparent" CornerRadius="{../CornerRadius}" BorderWidth="1"
+ MouseEnter="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black}"
+ MouseLeave="{Foreground=Transparent}"
+ MouseDown="{Foreground=vgradient|0:Black|0.05:Grey|0.85:Grey|1:White};{Background=Yellow}"
+ MouseUp="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black};{Background=DarkGrey}">
+ <CheckBox Focusable="False" Width="Stretched" Height="Stretched" IsChecked="{²IsToggled}"
+ Checked="{Background=${ControlHighlight}}"
+ Unchecked="{Background=Jet}">
+ <Template>
+ <Image Style="icon" Name="caption" Path="{Icon}" Background="{./Background}" Margin="10"/>
+ </Template>
+ </CheckBox>
+ </Border>
+ </Template>
+ </Button>
+ <Button Command="{CMDToggleBoolVal}">
+ <Template>
+ <Container DataSource="{./Command}">
+<!-- <CheckBox Caption="{./Caption}" Style="CheckBox2" IsChecked="{²IsToggled}"/>-->
+ <CheckBox Width="Stretched" Height="Stretched" IsChecked="{²IsToggled}"
+ Checked="{Background=${ControlHighlight}}"
+ Unchecked="{Background=Jet}">
+ <Template>
+ <Image Style="icon" Name="caption" Path="{Icon}" Background="{./Background}" Margin="10"/>
+ </Template>
+ </CheckBox>
+ </Container>
+ </Template>
+ </Button>
+ </HorizontalStack>
+ <HorizontalStack Fit="true">
+ <Button Command="{CMDToggleBoolValField}">
+ <Template>
+ <Container DataSource="{./Command}">
+ <CheckBox Caption="{./Caption}" Style="CheckBox2" IsChecked="{²IsToggled}"/>
+ </Container>
+ </Template>
+ </Button>
+ </HorizontalStack>
+</VerticalStack>
\ No newline at end of file