From abab1746cb4389db8ccea729343a5b8f05a7e95b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sat, 11 Sep 2021 14:52:55 +0000 Subject: [PATCH] move iface update interval check to avoid 100% cpu usage, EnumValueSelector.forceRadioButton for bitfields --- Crow/src/Interface.cs | 2 +- Crow/src/Widgets/EnumSelector.cs | 76 ++++++++++++------- Crow/src/Widgets/Window.cs | 44 +++++------ Directory.Build.props | 4 +- Samples/ShowCase/ShowCase.cs | 11 +-- .../Interfaces/Experimental/enumSelector.crow | 6 ++ 6 files changed, 85 insertions(+), 58 deletions(-) create mode 100644 Samples/common/ui/Interfaces/Experimental/enumSelector.crow diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 4bc33896..7bf8cb39 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -478,8 +478,8 @@ namespace Crow public virtual void UpdateFrame () { #if VKVG Update (); - Thread.Sleep (UPDATE_INTERVAL); #endif + Thread.Sleep (UPDATE_INTERVAL); } public virtual void Quit () => Glfw3.SetWindowShouldClose (hWin, 1); diff --git a/Crow/src/Widgets/EnumSelector.cs b/Crow/src/Widgets/EnumSelector.cs index c61e97f2..70782ee0 100644 --- a/Crow/src/Widgets/EnumSelector.cs +++ b/Crow/src/Widgets/EnumSelector.cs @@ -40,7 +40,7 @@ namespace Crow UInt32 bitFieldExcludeMask; Type enumType; bool enumTypeIsBitsfield, forceRadioButton; - string rbStyle, iconsPrefix, iconsExtension; + string itemStyle, iconsPrefix, iconsExtension; #endregion #region public properties @@ -67,18 +67,33 @@ namespace Crow } } /// - /// Enum values are presented with RadioButton controls. Here you may specify a template to use + /// Enum values are presented with RadioButton or CheckBox controls. Here you may specify a template to use /// for the radio buttons. /// - [DefaultValue (null)] + [DefaultValue (null)][Obsolete("Use ItemStyle instead")] public string RadioButtonStyle { - get => rbStyle; + get => itemStyle; set { - if (rbStyle == value) + if (itemStyle == value) return; - rbStyle = value; + itemStyle = value; forceRefresh (); - NotifyValueChangedAuto (rbStyle); + NotifyValueChangedAuto (itemStyle); + } + } + /// + /// Enum values are presented with RadioButton or CheckBox controls. Here you may specify a template to use + /// for the radio buttons. + /// + [DefaultValue (null)] + public string ItemStyle { + get => itemStyle; + set { + if (itemStyle == value) + return; + itemStyle = value; + forceRefresh (); + NotifyValueChangedAuto (itemStyle); } } /// @@ -97,7 +112,7 @@ namespace Crow } } /// - /// use to define the colors of the 3d border + /// Current Selected Value(s). /// [DefaultValue(null)] public virtual Enum EnumValue { @@ -106,19 +121,19 @@ namespace Crow if (enumValue == value) return; - enumValue = value; + enumValue = value; if (enumValue != null) { if (enumType != enumValue.GetType ()) { enumValueContainer.ClearChildren (); - enumType = enumValue.GetType (); - + enumType = enumValue.GetType (); + enumTypeIsBitsfield = enumType.CustomAttributes.Any (ca => ca.AttributeType == typeof(FlagsAttribute)); - if (enumTypeIsBitsfield) { - IML.Instantiator iTor = IFace.CreateITorFromIMLFragment ($""); - UInt32 currentValue = Convert.ToUInt32 (EnumValue); + if (enumTypeIsBitsfield && !forceRadioButton) { + IML.Instantiator iTor = IFace.CreateITorFromIMLFragment ($""); + UInt32 currentValue = Convert.ToUInt32 (EnumValue); currentValue &= ~bitFieldExcludeMask; enumValue = (Enum)Enum.ToObject(enumType, currentValue); @@ -130,19 +145,19 @@ namespace Crow CheckBox rb = iTor.CreateInstance (); rb.Caption = en.ToString(); rb.LogicalParent = this; - rb.Tag = $"{iconsPrefix}{en}{IconsExtension}"; + rb.Tag = $"{iconsPrefix}{en}{IconsExtension}"; rb.Tooltip = $"0x{eni:x8}"; if (eni == 0) { rb.IsChecked = currentValue == 0; rb.Checked += (sender, e) => EnumValue = (Enum)Enum.ToObject(enumType, 0); - } else { + } else { rb.IsChecked = currentValue == 0 ? false : EnumValue.HasFlag (en); rb.Checked += onChecked; rb.Unchecked += onUnchecked; } /*rb.Checked += (sender, e) => (((CheckBox)sender).LogicalParent as EnumSelector).EnumValue = (Enum)(object) - (Convert.ToUInt32 ((((CheckBox)sender).LogicalParent as EnumSelector).EnumValue) | Convert.ToUInt32 (en)); + (Convert.ToUInt32 ((((CheckBox)sender).LogicalParent as EnumSelector).EnumValue) | Convert.ToUInt32 (en)); rb.Unchecked += (sender, e) => (((CheckBox)sender).LogicalParent as EnumSelector).EnumValue = (Enum)(object) (Convert.ToUInt32 ((((CheckBox)sender).LogicalParent as EnumSelector).EnumValue) & ~Convert.ToUInt32 (en)); */ @@ -150,23 +165,28 @@ namespace Crow } } else { - IML.Instantiator iTor = IFace.CreateITorFromIMLFragment ($""); + IML.Instantiator iTor = IFace.CreateITorFromIMLFragment ($""); foreach (var en in enumType.GetEnumValues ()) { + if (enumTypeIsBitsfield) { + UInt32 eni = Convert.ToUInt32 (en); + if ((eni & bitFieldExcludeMask) != 0) + continue; + } RadioButton rb = iTor.CreateInstance (); rb.Caption = en.ToString(); rb.LogicalParent = this; rb.Tag = $"{iconsPrefix}{en}{IconsExtension}"; - if (enumValue == en) - rb.IsChecked = true; + if (enumValue.Equals (en)) + rb.IsChecked = true; rb.Checked += (sender, e) => (((RadioButton)sender).LogicalParent as EnumSelector).EnumValue = (Enum)en; enumValueContainer.AddChild (rb); } } - - } else if (enumTypeIsBitsfield) { - UInt32 currentValue = Convert.ToUInt32 (EnumValue); + + } else if (enumTypeIsBitsfield && !forceRadioButton) { + UInt32 currentValue = Convert.ToUInt32 (EnumValue); currentValue &= ~bitFieldExcludeMask; enumValue = (Enum)Enum.ToObject(enumType, currentValue); @@ -219,17 +239,17 @@ namespace Crow forceRefresh(); } } - void onChecked (object sender, EventArgs e) { + void onChecked (object sender, EventArgs e) { Enum en =(Enum)Enum.Parse (enumType, (sender as CheckBox).Caption); UInt32 newVal = Convert.ToUInt32 (en); if (newVal == 0) - EnumValue = (Enum)Enum.ToObject(enumType, 0); + EnumValue = (Enum)Enum.ToObject(enumType, 0); else - EnumValue = (Enum)Enum.ToObject(enumType, newVal | Convert.ToUInt32 (EnumValue)); + EnumValue = (Enum)Enum.ToObject(enumType, newVal | Convert.ToUInt32 (EnumValue)); } - void onUnchecked (object sender, EventArgs e) { + void onUnchecked (object sender, EventArgs e) { Enum en =(Enum)Enum.Parse (enumType, (sender as CheckBox).Caption); - EnumValue = (Enum)Enum.ToObject(enumType, Convert.ToUInt32 (EnumValue) & ~Convert.ToUInt32 (en)); + EnumValue = (Enum)Enum.ToObject(enumType, Convert.ToUInt32 (EnumValue) & ~Convert.ToUInt32 (en)); } //force refresh to use new template if values are already displayed diff --git a/Crow/src/Widgets/Window.cs b/Crow/src/Widgets/Window.cs index a028c7d7..636b1bb5 100644 --- a/Crow/src/Widgets/Window.cs +++ b/Crow/src/Widgets/Window.cs @@ -32,12 +32,12 @@ namespace Crow string _icon; bool resizable; bool movable; - bool modal; + bool modal; bool alwaysOnTop = false; Rectangle savedBounds; bool wasResizable; - + Status currentState, allowedStates; protected Direction currentDirection = Direction.None; @@ -54,7 +54,7 @@ namespace Crow get => allowedStates; set { if (allowedStates == value) - return; + return; allowedStates = value; NotifyValueChangedAuto (allowedStates); @@ -80,7 +80,7 @@ namespace Crow [DefaultValue("Normal")] public Status CurrentState { get => currentState; - set { + set { Status newState = value; if (!allowedStates.HasFlag (newState)) { if (allowedStates.HasFlag (Status.Normal)) @@ -97,7 +97,7 @@ namespace Crow if (currentState == Status.Normal) { savedBounds = LastPaintedSlot; wasResizable = Resizable; - } + } currentState = value; NotifyValueChangedAuto (currentState); @@ -117,7 +117,7 @@ namespace Crow case Status.Minimized: Width = 200; Height = 20; - Resizable = false; + Resizable = false; CMDNormalize.CanExecute = allowedStates.HasFlag (Status.Normal); CMDMinimize.CanExecute = false; CMDMaximize.CanExecute = allowedStates.HasFlag (Status.Maximized); @@ -157,11 +157,11 @@ namespace Crow } /*public Command CMDMinimize = new Command ("Minimize", (sender) => {(sender as Window).CurrentState = Status.Minimized;}, "#Crow.Icons.minimize.svg", false); - public Command CMDMaximize = new Command ("Maximize", (sender) => + public Command CMDMaximize = new Command ("Maximize", (sender) => {(sender as Window).CurrentState = Status.Maximized;}, "#Crow.Icons.maximize.svg", false); - public Command CMDNormalize = new Command ("Normalize", (sender) => + public Command CMDNormalize = new Command ("Normalize", (sender) => {(sender as Window).CurrentState = Status.Normal;}, "#Crow.Icons.normalize.svg", false); - public Command CMDClose = new Command ("Close", (sender) => + public Command CMDClose = new Command ("Close", (sender) => {(sender as Window).close ();}, "#Crow.Icons.exit2.svg", true);*/ @@ -196,9 +196,9 @@ namespace Crow sizingHandle.MouseDown += setResizeOn; sizingHandle.MouseUp += setResizeOff; } - - if (moveHandle != null) { - moveHandle.MouseDown += setMoveOn; + + if (moveHandle != null) { + moveHandle.MouseDown += setMoveOn; moveHandle.MouseUp += setMoveOff; } } @@ -208,9 +208,9 @@ namespace Crow sizingHandle.MouseDown -= setResizeOn; sizingHandle.MouseUp -= setResizeOff; } - - if (moveHandle != null) { - moveHandle.MouseDown -= setMoveOn; + + if (moveHandle != null) { + moveHandle.MouseDown -= setMoveOn; moveHandle.MouseUp -= setMoveOff; } moveHandle = null; @@ -240,7 +240,7 @@ namespace Crow _icon = value; NotifyValueChangedAuto (_icon); } - } + } [DefaultValue(true)] public bool Resizable { get => resizable; @@ -263,7 +263,7 @@ namespace Crow } [DefaultValue(false)] public bool Modal { - get => modal; + get => modal; set { if (modal == value) return; @@ -273,11 +273,11 @@ namespace Crow } [DefaultValue(false)] public bool AlwaysOnTop { - get => modal ? true : alwaysOnTop; + get => modal ? true : alwaysOnTop; set { if (alwaysOnTop == value) return; - + alwaysOnTop = value; if (AlwaysOnTop && Parent != null) @@ -319,7 +319,7 @@ namespace Crow currentHeight = this.Slot.Height; if (move) { - this.Left = currentLeft + XDelta; + this.Left = currentLeft + XDelta; this.Top = currentTop + YDelta; return; } @@ -368,7 +368,7 @@ namespace Crow this.Height = currentHeight + YDelta; this.Width = currentWidth + XDelta; break; - } + } //} } @@ -479,7 +479,7 @@ namespace Crow protected void onMinimized (){ lock (IFace.LayoutMutex) { if (IsNormal) - + } Minimize.Raise (this, null); diff --git a/Directory.Build.props b/Directory.Build.props index 81510eed..fe1f22e3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,9 +3,9 @@ $(SolutionDir)build\$(Configuration)\ $(SolutionDir)build\obj\$(Configuration)\ MIT - Jean-Philippe Bruyère + Jean-Philippe Bruyère 7.3 - + 0.9.6 $(CrowVersion)-beta diff --git a/Samples/ShowCase/ShowCase.cs b/Samples/ShowCase/ShowCase.cs index 66e1f43e..5aa36fa7 100644 --- a/Samples/ShowCase/ShowCase.cs +++ b/Samples/ShowCase/ShowCase.cs @@ -30,10 +30,11 @@ namespace ShowCase app.SetWindowIcon ("#Crow.Icons.crow.png"); //app.Theme = @"C:\Users\Jean-Philippe\source\Crow\Themes\TestTheme"; CurrentProgramInstance = app; + app.Run (); } - } - public Container crowContainer; + } + public Container crowContainer; Stopwatch reloadChrono = new Stopwatch (); @@ -45,11 +46,11 @@ namespace ShowCase source = value; CMDSave.CanExecute = IsDirty; if (!reloadChrono.IsRunning) - reloadChrono.Restart (); + reloadChrono.Restart (); NotifyValueChanged (source); NotifyValueChanged ("IsDirty", IsDirty); } - } + } void reloadFromSource () { hideError (); @@ -63,7 +64,7 @@ namespace ShowCase crowContainer.SetChild (g); g.DataSource = this; } - } catch (InstantiatorException itorex) { + } catch (InstantiatorException itorex) { showError (itorex); } catch (Exception ex) { showError (ex); diff --git a/Samples/common/ui/Interfaces/Experimental/enumSelector.crow b/Samples/common/ui/Interfaces/Experimental/enumSelector.crow new file mode 100644 index 00000000..90eaa9a3 --- /dev/null +++ b/Samples/common/ui/Interfaces/Experimental/enumSelector.crow @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file -- 2.47.3