From da7dae31670d58e4e235ec924cced959b3d0bdcb Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 08:30:25 +0300 Subject: [PATCH 01/21] Shared - Drawing settings and Bars mode --- .../Controllers/PreferencesViewController.cs | 59 ++++++++++++++++++- .../Models/Configuration.cs | 25 ++++++++ .../Models/DrawingDirection.cs | 12 ++++ NickvisionCavalier.Shared/Models/Renderer.cs | 53 +++++++++++++++-- 4 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 NickvisionCavalier.Shared/Models/DrawingDirection.cs diff --git a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs index f551d8b..0972b97 100644 --- a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs +++ b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs @@ -164,13 +164,68 @@ public bool ReverseOrder set => Configuration.Current.ReverseOrder = value; } + /// + /// Drawing direction + /// + public DrawingDirection Direction + { + get => Configuration.Current.Direction; + + set => Configuration.Current.Direction = value; + } + + /// + /// The size of spaces between elements + /// + public float ItemsOffset + { + get => Configuration.Current.ItemsOffset; + + set => Configuration.Current.ItemsOffset = value; + } + + /// + /// Roundness of items (0 - square, 1 - round) + /// + public float ItemsRoundness + { + get => Configuration.Current.ItemsRoundness; + + set => Configuration.Current.ItemsRoundness = value; + } + + /// + /// Whether to fill or draw lines + /// + public bool Filling + { + get => Configuration.Current.Filling; + + set => Configuration.Current.Filling = value; + } + + /// + /// Thickness of lines when filling is off (in pixels) + /// + public uint LinesThickness + { + get => Configuration.Current.LinesThickness; + + set => Configuration.Current.LinesThickness = value; + } + + /// + /// Saves the configuration to disk + /// + public void Save() => Configuration.Current.Save(); + /// /// Occurs when a window's setting has changed /// public void ChangeWindowSettings() { OnWindowSettingsChanged?.Invoke(this, EventArgs.Empty); - Configuration.Current.Save(); + Save(); } /// @@ -179,6 +234,6 @@ public void ChangeWindowSettings() public void ChangeCavaSettings() { OnCavaSettingsChanged?.Invoke(this, EventArgs.Empty); - Configuration.Current.Save(); + Save(); } } diff --git a/NickvisionCavalier.Shared/Models/Configuration.cs b/NickvisionCavalier.Shared/Models/Configuration.cs index b75cac2..0d6844b 100644 --- a/NickvisionCavalier.Shared/Models/Configuration.cs +++ b/NickvisionCavalier.Shared/Models/Configuration.cs @@ -77,6 +77,26 @@ public class Configuration /// Whether to reverse bars order for each channel /// public bool ReverseOrder { get; set; } + /// + /// Drawing direction + /// + public DrawingDirection Direction { get; set; } + /// + /// The size of spaces between elements + /// + public float ItemsOffset { get; set; } + /// + /// Roundness of items (0 - square, 1 - round) + /// + public float ItemsRoundness { get; set; } + /// + /// Whether to fill or draw lines + /// + public bool Filling { get; set; } + /// + /// Thickness of lines when filling is off (in pixels) + /// + public uint LinesThickness { get; set; } /// /// Occurs when the configuration is saved to disk @@ -108,6 +128,11 @@ public Configuration() Monstercat = true; NoiseReduction = 0.77f; ReverseOrder = true; + Direction = DrawingDirection.BottomTop; + ItemsOffset = 0.1f; + ItemsRoundness = 0.5f; + Filling = true; + LinesThickness = 15; } /// diff --git a/NickvisionCavalier.Shared/Models/DrawingDirection.cs b/NickvisionCavalier.Shared/Models/DrawingDirection.cs new file mode 100644 index 0000000..38c0b4f --- /dev/null +++ b/NickvisionCavalier.Shared/Models/DrawingDirection.cs @@ -0,0 +1,12 @@ +namespace NickvisionCavalier.Shared.Models; + +/// +/// Drawing direction +/// +public enum DrawingDirection +{ + TopBottom = 0, + BottomTop, + LeftRight, + RightLeft +} \ No newline at end of file diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 478e80b..469fc94 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -4,6 +4,12 @@ namespace NickvisionCavalier.Shared.Models; public class Renderer { + private DrawingDirection _direction => Configuration.Current.Direction; + private float _offset => Configuration.Current.ItemsOffset; + private float _roundness => Configuration.Current.ItemsRoundness; + private bool _fill => Configuration.Current.Filling; + private uint _thickness => Configuration.Current.LinesThickness; + public SKCanvas? Canvas { get; set; } public Renderer() @@ -18,20 +24,59 @@ public void Draw(float[] sample, float width, float height) return; } Canvas.Clear(); + DrawBarsBox(sample, width, height); + Canvas.Flush(); + } + + private void DrawBarsBox(float[] sample, float width, float height) + { var paint = new SKPaint { - Style = SKPaintStyle.Fill, + Style = _fill ? SKPaintStyle.Fill : SKPaintStyle.Stroke, Color = SKColors.Blue }; - var step = width / sample.Length; + var step = (_direction < DrawingDirection.LeftRight ? width : height) / sample.Length; for (var i = 0; i < sample.Length; i++) { if (sample[i] == 0) { continue; } - Canvas.DrawRect(step * (i + 0.1f), height * (1 - sample[i]), step * 0.8f, height * sample[i], paint); + switch (_direction) + { + case DrawingDirection.TopBottom: + Canvas.DrawRect( + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + 0, + step * (1 - _offset) - (_fill ? 0 : _thickness), + height * sample[i], + paint); + break; + case DrawingDirection.BottomTop: + Canvas.DrawRect( + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + height * (1 - sample[i]), + step * (1 - _offset) - (_fill ? 0 : _thickness), + height * sample[i], + paint); + break; + case DrawingDirection.LeftRight: + Canvas.DrawRect( + 0, + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + width * sample[i], + step * (1 - _offset) - (_fill ? 0 : _thickness), + paint); + break; + case DrawingDirection.RightLeft: + Canvas.DrawRect( + width * (1 - sample[i]), + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + width * sample[i], + step * (1 - _offset) - (_fill ? 0 : _thickness), + paint); + break; + }; } - Canvas.Flush(); } } From a5ad5c13e8d9be10141b8b6a1265c16c5290f65d Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:10:19 +0300 Subject: [PATCH 02/21] GNOME - Add drawing settings --- .../Blueprints/preferences_dialog.blp | 71 +++++++++++++++++++ .../Views/PreferencesDialog.cs | 43 +++++++++++ 2 files changed, 114 insertions(+) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 7db5e9d..ce27fe4 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -31,6 +31,77 @@ Adw.PreferencesWindow _root { }; } } + + Adw.ComboRow _directionRow { + title: _("Drawing direction"); + model: Gtk.StringList { + strings ["Top to bottom", "Bottom to top", "Left to right", "Right to left" ] + }; + } + + Adw.ActionRow { + title: _("Offset between items"); + subtitle: _("The size of spaces between elements (in percent)."); + + [suffix] + Gtk.Scale _offsetScale { + width-request: 180; + draw-value: true; + value-pos: left; + digits: 0; + adjustment: Gtk.Adjustment { + lower: 0; + upper: 20; + step-increment: 1; + }; + } + } + + Adw.ActionRow { + title: _("Roundness of items"); + subtitle: _("How much rounded the elements should be (in percent)."); + + [suffix] + Gtk.Scale _roundnessScale { + width-request: 180; + draw-value: true; + value-pos: left; + digits: 0; + adjustment: Gtk.Adjustment { + lower: 0; + upper: 100; + step-increment: 1; + }; + } + } + + Adw.ActionRow { + title: _("Filling"); + subtitle: _("Whether shapes should be filled or outlined."); + + [suffix] + Gtk.Switch _fillingSwitch { + valign: center; + } + } + + Adw.ActionRow { + title: _("Thickness of lines"); + subtitle: _("Thickness of lines when filling is off (in pixels)."); + + [suffix] + Gtk.Scale _thicknessScale { + width-request: 180; + draw-value: true; + value-pos: left; + digits: 0; + adjustment: Gtk.Adjustment { + lower: 1; + upper: 40; + step-increment: 1; + }; + } + } } Adw.PreferencesGroup { diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index 1815899..06da138 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -1,5 +1,6 @@ using NickvisionCavalier.GNOME.Helpers; using NickvisionCavalier.Shared.Controllers; +using NickvisionCavalier.Shared.Models; namespace NickvisionCavalier.GNOME.Views; @@ -12,6 +13,11 @@ public partial class PreferencesDialog : Adw.PreferencesWindow private readonly Adw.Application _application; [Gtk.Connect] private readonly Gtk.Scale _marginScale; + [Gtk.Connect] private readonly Adw.ComboRow _directionRow; + [Gtk.Connect] private readonly Gtk.Scale _offsetScale; + [Gtk.Connect] private readonly Gtk.Scale _roundnessScale; + [Gtk.Connect] private readonly Gtk.Switch _fillingSwitch; + [Gtk.Connect] private readonly Gtk.Scale _thicknessScale; [Gtk.Connect] private readonly Gtk.Switch _borderlessSwitch; [Gtk.Connect] private readonly Gtk.Switch _sharpCornersSwitch; [Gtk.Connect] private readonly Gtk.Switch _windowControlsSwitch; @@ -38,6 +44,42 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _controller.AreaMargin = (uint)_marginScale.GetValue(); _controller.ChangeWindowSettings(); }; + _directionRow.SetSelected((uint)_controller.Direction); + _directionRow.OnNotify += (sender, e) => + { + if (e.Pspec.GetName() == "selected") + { + _controller.Direction = (DrawingDirection)_directionRow.GetSelected(); + _controller.Save(); + } + }; + _offsetScale.SetValue((int)(_controller.ItemsOffset * 100)); + _offsetScale.OnValueChanged += (sender, e) => + { + _controller.ItemsOffset = (float)_offsetScale.GetValue() / 100.0f; + _controller.Save(); + }; + _roundnessScale.SetValue((int)(_controller.ItemsRoundness * 100)); + _roundnessScale.OnValueChanged += (sender, e) => + { + _controller.ItemsRoundness = (float)_roundnessScale.GetValue() / 100.0f; + _controller.Save(); + }; + _fillingSwitch.SetActive(_controller.Filling); + _fillingSwitch.OnNotify += (sender, e) => + { + if (e.Pspec.GetName() == "active") + { + _controller.Filling = _fillingSwitch.GetActive(); + _controller.Save(); + } + }; + _thicknessScale.SetValue((int)_controller.LinesThickness); + _thicknessScale.OnValueChanged += (sender, e) => + { + _controller.LinesThickness = (uint)_thicknessScale.GetValue(); + _controller.Save(); + }; _borderlessSwitch.SetActive(_controller.Borderless); _borderlessSwitch.OnNotify += (sender, e) => { @@ -138,6 +180,7 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control if (e.Pspec.GetName() == "active") { _controller.ReverseOrder = _reverseSwitch.GetActive(); + _controller.Save(); } }; } From 980a5448b2fcf5327f13331590b1ccbc2571dc71 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:40:58 +0300 Subject: [PATCH 03/21] All - Adjust thickness, fix Bars mode --- .../Blueprints/preferences_dialog.blp | 4 ++-- .../Views/PreferencesDialog.cs | 5 ++++- .../Controllers/PreferencesViewController.cs | 2 +- .../Models/Configuration.cs | 2 +- NickvisionCavalier.Shared/Models/Renderer.cs | 19 ++++++++++--------- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index ce27fe4..910f602 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -85,7 +85,7 @@ Adw.PreferencesWindow _root { } } - Adw.ActionRow { + Adw.ActionRow _thicknessRow { title: _("Thickness of lines"); subtitle: _("Thickness of lines when filling is off (in pixels)."); @@ -97,7 +97,7 @@ Adw.PreferencesWindow _root { digits: 0; adjustment: Gtk.Adjustment { lower: 1; - upper: 40; + upper: 10; step-increment: 1; }; } diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index 06da138..f8af538 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -17,6 +17,7 @@ public partial class PreferencesDialog : Adw.PreferencesWindow [Gtk.Connect] private readonly Gtk.Scale _offsetScale; [Gtk.Connect] private readonly Gtk.Scale _roundnessScale; [Gtk.Connect] private readonly Gtk.Switch _fillingSwitch; + [Gtk.Connect] private readonly Adw.ActionRow _thicknessRow; [Gtk.Connect] private readonly Gtk.Scale _thicknessScale; [Gtk.Connect] private readonly Gtk.Switch _borderlessSwitch; [Gtk.Connect] private readonly Gtk.Switch _sharpCornersSwitch; @@ -71,13 +72,15 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control if (e.Pspec.GetName() == "active") { _controller.Filling = _fillingSwitch.GetActive(); + _thicknessRow.SetSensitive(!_fillingSwitch.GetActive()); _controller.Save(); } }; + _thicknessRow.SetSensitive(!_fillingSwitch.GetActive()); _thicknessScale.SetValue((int)_controller.LinesThickness); _thicknessScale.OnValueChanged += (sender, e) => { - _controller.LinesThickness = (uint)_thicknessScale.GetValue(); + _controller.LinesThickness = (float)_thicknessScale.GetValue(); _controller.Save(); }; _borderlessSwitch.SetActive(_controller.Borderless); diff --git a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs index 0972b97..bada7ea 100644 --- a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs +++ b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs @@ -207,7 +207,7 @@ public bool Filling /// /// Thickness of lines when filling is off (in pixels) /// - public uint LinesThickness + public float LinesThickness { get => Configuration.Current.LinesThickness; diff --git a/NickvisionCavalier.Shared/Models/Configuration.cs b/NickvisionCavalier.Shared/Models/Configuration.cs index 0d6844b..b4ccfa5 100644 --- a/NickvisionCavalier.Shared/Models/Configuration.cs +++ b/NickvisionCavalier.Shared/Models/Configuration.cs @@ -96,7 +96,7 @@ public class Configuration /// /// Thickness of lines when filling is off (in pixels) /// - public uint LinesThickness { get; set; } + public float LinesThickness { get; set; } /// /// Occurs when the configuration is saved to disk diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 469fc94..2db4081 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -8,7 +8,7 @@ public class Renderer private float _offset => Configuration.Current.ItemsOffset; private float _roundness => Configuration.Current.ItemsRoundness; private bool _fill => Configuration.Current.Filling; - private uint _thickness => Configuration.Current.LinesThickness; + private float _thickness => (float)Configuration.Current.LinesThickness; public SKCanvas? Canvas { get; set; } @@ -33,6 +33,7 @@ private void DrawBarsBox(float[] sample, float width, float height) var paint = new SKPaint { Style = _fill ? SKPaintStyle.Fill : SKPaintStyle.Stroke, + StrokeWidth = _thickness, Color = SKColors.Blue }; var step = (_direction < DrawingDirection.LeftRight ? width : height) / sample.Length; @@ -47,32 +48,32 @@ private void DrawBarsBox(float[] sample, float width, float height) case DrawingDirection.TopBottom: Canvas.DrawRect( step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - 0, + _fill ? 0 : _thickness / 2, step * (1 - _offset) - (_fill ? 0 : _thickness), - height * sample[i], + height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.BottomTop: Canvas.DrawRect( step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - height * (1 - sample[i]), + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), step * (1 - _offset) - (_fill ? 0 : _thickness), - height * sample[i], + height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.LeftRight: Canvas.DrawRect( - 0, + _fill ? 0 : _thickness / 2, step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - width * sample[i], + width * sample[i] - (_fill ? 0 : _thickness), step * (1 - _offset) - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.RightLeft: Canvas.DrawRect( - width * (1 - sample[i]), + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - width * sample[i], + width * sample[i] - (_fill ? 0 : _thickness), step * (1 - _offset) - (_fill ? 0 : _thickness), paint); break; From 8ffc81686227ece3bf246deba0cbaf27c7c1fbb1 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:52:22 +0300 Subject: [PATCH 04/21] GNOME - Preferences window, set activatable widgets --- .../Blueprints/preferences_dialog.blp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 910f602..99b826d 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -78,6 +78,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Filling"); subtitle: _("Whether shapes should be filled or outlined."); + activatable-widget: _fillingSwitch; [suffix] Gtk.Switch _fillingSwitch { @@ -108,6 +109,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Borderless window"); subtitle: _("Whether to disable window shadow and borders."); + activatable-widget: _borderlessSwitch; [suffix] Gtk.Switch _borderlessSwitch { @@ -118,6 +120,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Sharp corners"); subtitle: _("Whether the main window corners should be sharp."); + activatable-widget: _sharpCornersSwitch; [suffix] Gtk.Switch _sharpCornersSwitch { @@ -128,6 +131,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Window controls"); subtitle: _("Whether to show window control buttons."); + activatable-widget: _windowControlsSwitch; [suffix] Gtk.Switch _windowControlsSwitch { @@ -138,6 +142,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Autohide headerbar"); subtitle: _("Whether to hide headerbar when main window is not focused."); + activatable-widget: _autohideHeaderSwitch; [suffix] Gtk.Switch _autohideHeaderSwitch { @@ -180,6 +185,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Automatic sensitivity"); subtitle: _("Attempt to decrease sensitivity if the bars peak."); + activatable-widget: _autosensSwitch; [suffix] Gtk.Switch _autosensSwitch { @@ -226,6 +232,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Monstercat smoothing"); subtitle: _("Whether to enable the so-called «Monstercat smoothing»."); + activatable-widget: _monstercatSwitch; [suffix] Gtk.Switch _monstercatSwitch { @@ -254,6 +261,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Reverse order"); subtitle: _("Whether to reverse order of bars for each channel."); + activatable-widget: _reverseSwitch; [suffix] Gtk.Switch _reverseSwitch { From 52d9d4ffc00f01511a56716cd2f311fbc758cdc7 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:10:15 +0300 Subject: [PATCH 05/21] GNOME - Limit noise reduction --- NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 99b826d..c516f08 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -242,7 +242,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow { title: _("Noise reduction"); - subtitle: _("This factor adjusts the integral and gravity filters to keep the signal smooth.\n1 will be very slow and smooth, 0 will be fast but noisy."); + subtitle: _("This factor adjusts the integral and gravity filters to keep the signal smooth.\nHigher value leads to a slower and smoother result."); [suffix] Gtk.Scale _noiseReductionScale { @@ -251,8 +251,8 @@ Adw.PreferencesWindow _root { value-pos: left; digits: 2; adjustment: Gtk.Adjustment { - lower: 0.0; - upper: 1.0; + lower: 0.15; + upper: 0.95; step-increment: 0.01; }; } From 3850ec1c59cd429b7abdee5f6b6ed806cc6110fc Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:28:38 +0300 Subject: [PATCH 06/21] Shared - Update devel icon --- .../org.nickvision.cavalier-devel.svg | 3040 ++++++++++++++++- 1 file changed, 2968 insertions(+), 72 deletions(-) diff --git a/NickvisionCavalier.Shared/Resources/org.nickvision.cavalier-devel.svg b/NickvisionCavalier.Shared/Resources/org.nickvision.cavalier-devel.svg index 51c42ba..b5bbbe9 100644 --- a/NickvisionCavalier.Shared/Resources/org.nickvision.cavalier-devel.svg +++ b/NickvisionCavalier.Shared/Resources/org.nickvision.cavalier-devel.svg @@ -1,75 +1,2971 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3ef35e8e26152cc630251325a78751b557d4eb83 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 23:18:30 +0300 Subject: [PATCH 07/21] Shared - Wave drawing mode --- .../Controllers/PreferencesViewController.cs | 10 ++ .../Models/Configuration.cs | 5 + .../Models/DrawingMode.cs | 9 ++ NickvisionCavalier.Shared/Models/Renderer.cs | 109 ++++++++++++++++-- 4 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 NickvisionCavalier.Shared/Models/DrawingMode.cs diff --git a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs index bada7ea..a37b0c5 100644 --- a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs +++ b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs @@ -214,6 +214,16 @@ public float LinesThickness set => Configuration.Current.LinesThickness = value; } + /// + /// Active drawing mode + /// + public DrawingMode Mode + { + get => Configuration.Current.Mode; + + set => Configuration.Current.Mode = value; + } + /// /// Saves the configuration to disk /// diff --git a/NickvisionCavalier.Shared/Models/Configuration.cs b/NickvisionCavalier.Shared/Models/Configuration.cs index b4ccfa5..1bba36c 100644 --- a/NickvisionCavalier.Shared/Models/Configuration.cs +++ b/NickvisionCavalier.Shared/Models/Configuration.cs @@ -97,6 +97,10 @@ public class Configuration /// Thickness of lines when filling is off (in pixels) /// public float LinesThickness { get; set; } + /// + /// Active drawing mode + /// + public DrawingMode Mode { get; set; } /// /// Occurs when the configuration is saved to disk @@ -133,6 +137,7 @@ public Configuration() ItemsRoundness = 0.5f; Filling = true; LinesThickness = 15; + Mode = DrawingMode.WaveBox; } /// diff --git a/NickvisionCavalier.Shared/Models/DrawingMode.cs b/NickvisionCavalier.Shared/Models/DrawingMode.cs new file mode 100644 index 0000000..76261a9 --- /dev/null +++ b/NickvisionCavalier.Shared/Models/DrawingMode.cs @@ -0,0 +1,9 @@ +namespace NickvisionCavalier.Shared.Models; + +public enum DrawingMode { + WaveBox = 0, + LevelsBox, + ParticlesBox, + BarsBox, + SpineBox +} \ No newline at end of file diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 2db4081..955b38c 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -24,18 +24,113 @@ public void Draw(float[] sample, float width, float height) return; } Canvas.Clear(); - DrawBarsBox(sample, width, height); - Canvas.Flush(); - } - - private void DrawBarsBox(float[] sample, float width, float height) - { - var paint = new SKPaint + var fgPaint = new SKPaint { Style = _fill ? SKPaintStyle.Fill : SKPaintStyle.Stroke, StrokeWidth = _thickness, Color = SKColors.Blue }; + switch (Configuration.Current.Mode) + { + case DrawingMode.WaveBox: + DrawWaveBox(sample, width, height, fgPaint); + break; + case DrawingMode.BarsBox: + DrawBarsBox(sample, width, height, fgPaint); + break; + } + Canvas.Flush(); + } + + private void DrawWaveBox(float[] sample, float width, float height, SKPaint paint) + { + var step = (_direction < DrawingDirection.LeftRight ? width : height) / (sample.Length - 1); + var path = new SKPath(); + switch (_direction) + { + case DrawingDirection.TopBottom: + path.MoveTo(0, height * sample[0] - (_fill ? 0 : _thickness / 2)); + for (var i = 0; i < sample.Length - 1; i++) + { + path.CubicTo( + step * (i + 0.5f), + height * sample[i] - (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + height * sample[i+1] - (_fill ? 0 : _thickness / 2), + step * (i + 1), + height * sample[i+1] - (_fill ? 0 : _thickness / 2)); + } + if (_fill) + { + path.LineTo(width, 0); + path.LineTo(0, 0); + path.Close(); + } + break; + case DrawingDirection.BottomTop: + path.MoveTo(0, height * (1 - sample[0]) + (_fill ? 0 : _thickness / 2)); + for (var i = 0; i < sample.Length - 1; i++) + { + path.CubicTo( + step * (i + 0.5f), + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + step * (i + 1), + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2)); + } + if (_fill) + { + path.LineTo(width, height); + path.LineTo(0, height); + path.Close(); + } + break; + case DrawingDirection.LeftRight: + path.MoveTo(width * sample[0] - (_fill ? 0 : _thickness / 2), 0); + for (var i = 0; i < sample.Length - 1; i++) + { + path.CubicTo( + width * sample[i] - (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + step * (i + 1)); + } + if (_fill) + { + path.LineTo(0, height); + path.LineTo(0, 0); + path.Close(); + } + break; + case DrawingDirection.RightLeft: + path.MoveTo(width * (1 - sample[0]) + (_fill ? 0 : _thickness / 2), 0); + for (var i = 0; i < sample.Length - 1; i++) + { + path.CubicTo( + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + step * (i + 0.5f), + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + step * (i + 1)); + } + if (_fill) + { + path.LineTo(width, height); + path.LineTo(width, 0); + path.Close(); + } + break; + } + Canvas.DrawPath(path, paint); + path.Dispose(); + } + + private void DrawBarsBox(float[] sample, float width, float height, SKPaint paint) + { var step = (_direction < DrawingDirection.LeftRight ? width : height) / sample.Length; for (var i = 0; i < sample.Length; i++) { From 4ebade82f0e657251523d0e0059f66d71b7fbcd2 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 23:19:15 +0300 Subject: [PATCH 08/21] GNOME - Remove devel css class --- NickvisionCavalier.GNOME/Views/MainWindow.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/NickvisionCavalier.GNOME/Views/MainWindow.cs b/NickvisionCavalier.GNOME/Views/MainWindow.cs index b3dff0d..5433555 100644 --- a/NickvisionCavalier.GNOME/Views/MainWindow.cs +++ b/NickvisionCavalier.GNOME/Views/MainWindow.cs @@ -30,10 +30,6 @@ private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.App SetDefaultSize((int)_controller.WindowWidth, (int)_controller.WindowHeight); SetTitle(_controller.AppInfo.ShortName); SetIconName(_controller.AppInfo.ID); - if (_controller.IsDevVersion) - { - AddCssClass("devel"); - } //Build UI builder.Connect(this); _drawingView = new DrawingView(new DrawingViewController()); From 54a4bc3606729fa009671ed199630010be9f83cf Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Fri, 9 Jun 2023 23:27:01 +0300 Subject: [PATCH 09/21] GNOME - Allow only one preferences dialog --- .../Blueprints/preferences_dialog.blp | 2 +- NickvisionCavalier.GNOME/Views/MainWindow.cs | 21 ++++++------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index c516f08..07f5ebb 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -6,7 +6,7 @@ Adw.PreferencesWindow _root { default-height: 400; modal: false; destroy-with-parent: true; - hide-on-close: false; + hide-on-close: true; title: _("Preferences"); Adw.PreferencesPage { diff --git a/NickvisionCavalier.GNOME/Views/MainWindow.cs b/NickvisionCavalier.GNOME/Views/MainWindow.cs index 5433555..179708a 100644 --- a/NickvisionCavalier.GNOME/Views/MainWindow.cs +++ b/NickvisionCavalier.GNOME/Views/MainWindow.cs @@ -21,6 +21,7 @@ public class MainWindow : Adw.ApplicationWindow private readonly MainWindowController _controller; private readonly Adw.Application _application; private readonly DrawingView _drawingView; + private readonly PreferencesDialog _preferencesDialog; private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.Application application) : base(builder.GetPointer("_root"), false) { @@ -34,6 +35,10 @@ private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.App builder.Connect(this); _drawingView = new DrawingView(new DrawingViewController()); _overlay.SetChild(_drawingView); + var prefController = _controller.CreatePreferencesViewController(); + prefController.OnWindowSettingsChanged += UpdateWindowSettings; + prefController.OnCavaSettingsChanged += _drawingView.UpdateCavaSettings; + _preferencesDialog = new PreferencesDialog(prefController, _application, this); UpdateWindowSettings(null, EventArgs.Empty); OnNotify += (sender, e) => { @@ -49,7 +54,7 @@ private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.App }; //Preferences Action var actPreferences = Gio.SimpleAction.New("preferences", null); - actPreferences.OnActivate += Preferences; + actPreferences.OnActivate += (sender, e) => _preferencesDialog.Present(); AddAction(actPreferences); application.SetAccelsForAction("win.preferences", new string[] { "comma" }); //Keyboard Shortcuts Action @@ -87,20 +92,6 @@ public void Start() Present(); } - /// - /// Occurs when the preferences action is triggered - /// - /// Gio.SimpleAction - /// EventArgs - private void Preferences(Gio.SimpleAction sender, EventArgs e) - { - var prefController = _controller.CreatePreferencesViewController(); - prefController.OnWindowSettingsChanged += UpdateWindowSettings; - prefController.OnCavaSettingsChanged += _drawingView.UpdateCavaSettings; - var preferencesDialog = new PreferencesDialog(prefController, _application, this); - preferencesDialog.Present(); - } - /// /// Occurs when settings for the window have changed /// From 986dbe410a131316e7a57cf9d6a88dbe7d621fc9 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Sat, 10 Jun 2023 00:00:59 +0300 Subject: [PATCH 10/21] GNOME - Drawing mode switching --- .../Blueprints/preferences_dialog.blp | 29 +++++++++++++++-- .../Views/PreferencesDialog.cs | 32 ++++++++++++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 07f5ebb..8e63f65 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -3,7 +3,7 @@ using Adw 1; Adw.PreferencesWindow _root { default-width: 600; - default-height: 400; + default-height: 500; modal: false; destroy-with-parent: true; hide-on-close: true; @@ -13,6 +13,28 @@ Adw.PreferencesWindow _root { title: _("Cavalier"); icon-name: "org.nickvision.cavalier-symbolic"; + Adw.PreferencesGroup { + title: _("Drawing mode"); + + Adw.ActionRow { + title: _("Wave"); + activatable-widget: _waveCheckButton; + + [prefix] + Gtk.CheckButton _waveCheckButton {} + } + + Adw.ActionRow { + title: _("Bars"); + activatable-widget: _barsCheckButton; + + [prefix] + Gtk.CheckButton _barsCheckButton { + group: _waveCheckButton; + } + } + } + Adw.PreferencesGroup { Adw.ActionRow { title: _("Drawing area margin"); @@ -39,7 +61,7 @@ Adw.PreferencesWindow _root { }; } - Adw.ActionRow { + Adw.ActionRow _offsetRow { title: _("Offset between items"); subtitle: _("The size of spaces between elements (in percent)."); @@ -57,7 +79,7 @@ Adw.PreferencesWindow _root { } } - Adw.ActionRow { + Adw.ActionRow _roundnessRow { title: _("Roundness of items"); subtitle: _("How much rounded the elements should be (in percent)."); @@ -89,6 +111,7 @@ Adw.PreferencesWindow _root { Adw.ActionRow _thicknessRow { title: _("Thickness of lines"); subtitle: _("Thickness of lines when filling is off (in pixels)."); + sensitive: bind _fillingSwitch.active inverted; [suffix] Gtk.Scale _thicknessScale { diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index f8af538..23b62fa 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -12,9 +12,13 @@ public partial class PreferencesDialog : Adw.PreferencesWindow private readonly PreferencesViewController _controller; private readonly Adw.Application _application; + [Gtk.Connect] private readonly Gtk.CheckButton _waveCheckButton; + [Gtk.Connect] private readonly Gtk.CheckButton _barsCheckButton; [Gtk.Connect] private readonly Gtk.Scale _marginScale; [Gtk.Connect] private readonly Adw.ComboRow _directionRow; + [Gtk.Connect] private readonly Adw.ActionRow _offsetRow; [Gtk.Connect] private readonly Gtk.Scale _offsetScale; + [Gtk.Connect] private readonly Adw.ActionRow _roundnessRow; [Gtk.Connect] private readonly Gtk.Scale _roundnessScale; [Gtk.Connect] private readonly Gtk.Switch _fillingSwitch; [Gtk.Connect] private readonly Adw.ActionRow _thicknessRow; @@ -39,6 +43,33 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control SetIconName(_controller.AppInfo.ID); //Build UI builder.Connect(this); + _waveCheckButton.OnToggled += (sender, e) => + { + if (_waveCheckButton.GetActive()) + { + _controller.Mode = DrawingMode.WaveBox; + _offsetRow.SetSensitive(false); + _roundnessRow.SetSensitive(false); + } + }; + _barsCheckButton.OnToggled += (sender, e) => + { + if (_barsCheckButton.GetActive()) + { + _controller.Mode = DrawingMode.BarsBox; + _offsetRow.SetSensitive(true); + _roundnessRow.SetSensitive(false); + } + }; + switch (_controller.Mode) + { + case DrawingMode.WaveBox: + _waveCheckButton.SetActive(true); + break; + case DrawingMode.BarsBox: + _barsCheckButton.SetActive(true); + break; + } _marginScale.SetValue((int)_controller.AreaMargin); _marginScale.OnValueChanged += (sender, e) => { @@ -72,7 +103,6 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control if (e.Pspec.GetName() == "active") { _controller.Filling = _fillingSwitch.GetActive(); - _thicknessRow.SetSensitive(!_fillingSwitch.GetActive()); _controller.Save(); } }; From b586269f75cacd116bd17511ccf0cfd7eb991b03 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev Date: Mon, 26 Jun 2023 19:59:04 +0300 Subject: [PATCH 11/21] GNOME - Avoid random freezes --- .../Blueprints/drawing_view.blp | 1 + NickvisionCavalier.GNOME/Views/DrawingView.cs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp index 99d9ec7..8750335 100644 --- a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp +++ b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp @@ -20,6 +20,7 @@ Gtk.Stack _root { child: Gtk.GLArea _glArea { hexpand: true; vexpand: true; + auto-render: false; }; } } \ No newline at end of file diff --git a/NickvisionCavalier.GNOME/Views/DrawingView.cs b/NickvisionCavalier.GNOME/Views/DrawingView.cs index 2b25273..b6969b2 100644 --- a/NickvisionCavalier.GNOME/Views/DrawingView.cs +++ b/NickvisionCavalier.GNOME/Views/DrawingView.cs @@ -12,8 +12,7 @@ namespace NickvisionCavalier.GNOME.Views; public partial class DrawingView : Gtk.Stack { [LibraryImport("libEGL.so.1", StringMarshalling = StringMarshalling.Utf8)] - private static partial IntPtr eglGetProcAddress(string name); - //TODO: GLX and WGL + private static partial nint eglGetProcAddress(string name); [LibraryImport("libGL.so.1", StringMarshalling = StringMarshalling.Utf8)] private static partial void glClear(uint mask); @@ -23,10 +22,20 @@ public partial class DrawingView : Gtk.Stack private GRContext? _ctx; private SKSurface? _skSurface; private float[]? _sample; + private System.Timers.Timer _antiFreezeTimer; private DrawingView(Gtk.Builder builder, DrawingViewController controller) : base(builder.GetPointer("_root"), false) { _controller = controller; + _antiFreezeTimer = new System.Timers.Timer(50); + _antiFreezeTimer.AutoReset = false; + _antiFreezeTimer.Elapsed += (sender, e) => + { + // GLArea can randomly freeze, stopping to react on QueueRender() + // Changing visibility is a workaround + SetVisible(false); + SetVisible(true); + }; //Build UI builder.Connect(this); _glArea.OnRealize += (sender, e) => @@ -44,6 +53,7 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas } _sample = sample; _glArea.QueueRender(); + _antiFreezeTimer.Start(); }; _glArea.OnRender += OnRender; } @@ -74,6 +84,7 @@ private void OnResize(Gtk.GLArea sender, EventArgs e) /// private bool OnRender(Gtk.GLArea sender, EventArgs e) { + _antiFreezeTimer.Stop(); if (_skSurface == null) { return false; From 382dc73ab70128856153a95739061e6689468579 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 02:01:13 +0300 Subject: [PATCH 12/21] GNOME - Avoid random freezes --- .../Blueprints/drawing_view.blp | 1 + NickvisionCavalier.GNOME/Views/DrawingView.cs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp index 99d9ec7..8750335 100644 --- a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp +++ b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp @@ -20,6 +20,7 @@ Gtk.Stack _root { child: Gtk.GLArea _glArea { hexpand: true; vexpand: true; + auto-render: false; }; } } \ No newline at end of file diff --git a/NickvisionCavalier.GNOME/Views/DrawingView.cs b/NickvisionCavalier.GNOME/Views/DrawingView.cs index 2b25273..b6969b2 100644 --- a/NickvisionCavalier.GNOME/Views/DrawingView.cs +++ b/NickvisionCavalier.GNOME/Views/DrawingView.cs @@ -12,8 +12,7 @@ namespace NickvisionCavalier.GNOME.Views; public partial class DrawingView : Gtk.Stack { [LibraryImport("libEGL.so.1", StringMarshalling = StringMarshalling.Utf8)] - private static partial IntPtr eglGetProcAddress(string name); - //TODO: GLX and WGL + private static partial nint eglGetProcAddress(string name); [LibraryImport("libGL.so.1", StringMarshalling = StringMarshalling.Utf8)] private static partial void glClear(uint mask); @@ -23,10 +22,20 @@ public partial class DrawingView : Gtk.Stack private GRContext? _ctx; private SKSurface? _skSurface; private float[]? _sample; + private System.Timers.Timer _antiFreezeTimer; private DrawingView(Gtk.Builder builder, DrawingViewController controller) : base(builder.GetPointer("_root"), false) { _controller = controller; + _antiFreezeTimer = new System.Timers.Timer(50); + _antiFreezeTimer.AutoReset = false; + _antiFreezeTimer.Elapsed += (sender, e) => + { + // GLArea can randomly freeze, stopping to react on QueueRender() + // Changing visibility is a workaround + SetVisible(false); + SetVisible(true); + }; //Build UI builder.Connect(this); _glArea.OnRealize += (sender, e) => @@ -44,6 +53,7 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas } _sample = sample; _glArea.QueueRender(); + _antiFreezeTimer.Start(); }; _glArea.OnRender += OnRender; } @@ -74,6 +84,7 @@ private void OnResize(Gtk.GLArea sender, EventArgs e) /// private bool OnRender(Gtk.GLArea sender, EventArgs e) { + _antiFreezeTimer.Stop(); if (_skSurface == null) { return false; From d0f24532e0a3cce0803256b3b7ed598f2241194a Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 05:41:27 +0300 Subject: [PATCH 13/21] GNOME - Mirror setting --- .../Blueprints/preferences_dialog.blp | 6 + .../Blueprints/window.blp | 4 +- NickvisionCavalier.GNOME/Views/DrawingView.cs | 27 +-- NickvisionCavalier.GNOME/Views/MainWindow.cs | 18 +- .../Views/PreferencesDialog.cs | 38 +++- .../Controllers/PreferencesViewController.cs | 10 + .../Models/Configuration.cs | 5 + NickvisionCavalier.Shared/Models/Mirror.cs | 11 ++ NickvisionCavalier.Shared/Models/Renderer.cs | 179 +++++++++++++----- 9 files changed, 227 insertions(+), 71 deletions(-) create mode 100644 NickvisionCavalier.Shared/Models/Mirror.cs diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 8e63f65..3e57f67 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -35,6 +35,12 @@ Adw.PreferencesWindow _root { } } + Adw.PreferencesGroup { + Adw.ComboRow _mirrorRow { + title: _("Mirror"); + } + } + Adw.PreferencesGroup { Adw.ActionRow { title: _("Drawing area margin"); diff --git a/NickvisionCavalier.GNOME/Blueprints/window.blp b/NickvisionCavalier.GNOME/Blueprints/window.blp index bf18040..c5b4d59 100644 --- a/NickvisionCavalier.GNOME/Blueprints/window.blp +++ b/NickvisionCavalier.GNOME/Blueprints/window.blp @@ -9,8 +9,8 @@ menu mainMenu { } Adw.ApplicationWindow _root { - width-request: 170; - height-request: 170; + width-request: 232; + height-request: 232; Gtk.Overlay _overlay { [overlay] diff --git a/NickvisionCavalier.GNOME/Views/DrawingView.cs b/NickvisionCavalier.GNOME/Views/DrawingView.cs index b6969b2..90caec0 100644 --- a/NickvisionCavalier.GNOME/Views/DrawingView.cs +++ b/NickvisionCavalier.GNOME/Views/DrawingView.cs @@ -15,15 +15,17 @@ public partial class DrawingView : Gtk.Stack private static partial nint eglGetProcAddress(string name); [LibraryImport("libGL.so.1", StringMarshalling = StringMarshalling.Utf8)] private static partial void glClear(uint mask); - + [Gtk.Connect] private readonly Gtk.GLArea _glArea; private readonly DrawingViewController _controller; private GRContext? _ctx; private SKSurface? _skSurface; private float[]? _sample; - private System.Timers.Timer _antiFreezeTimer; + private readonly System.Timers.Timer _antiFreezeTimer; + public event Action? OnFreeze; + private DrawingView(Gtk.Builder builder, DrawingViewController controller) : base(builder.GetPointer("_root"), false) { _controller = controller; @@ -32,9 +34,7 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas _antiFreezeTimer.Elapsed += (sender, e) => { // GLArea can randomly freeze, stopping to react on QueueRender() - // Changing visibility is a workaround - SetVisible(false); - SetVisible(true); + OnFreeze?.Invoke(); }; //Build UI builder.Connect(this); @@ -44,16 +44,16 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas var grInt = GRGlInterface.Create(eglGetProcAddress); _ctx = GRContext.CreateGl(grInt); }; - _glArea.OnResize += OnResize; + _glArea.OnResize += (sender, e) => CreateSurface(); _controller.Cava.OutputReceived += (sender, sample) => { if (GetVisibleChildName() != "gl") { SetVisibleChildName("gl"); } + _antiFreezeTimer.Start(); _sample = sample; _glArea.QueueRender(); - _antiFreezeTimer.Start(); }; _glArea.OnRender += OnRender; } @@ -67,16 +67,17 @@ public DrawingView(DrawingViewController controller) : this(Builder.FromFile("dr } /// - /// (Re)creates surface on area resize + /// (Re)creates drawing surface /// - /// Gtk.GLArea - /// EventArgs - private void OnResize(Gtk.GLArea sender, EventArgs e) + private void CreateSurface() { _skSurface?.Dispose(); - var imgInfo = new SKImageInfo(sender.GetAllocatedWidth(), sender.GetAllocatedHeight()); + var imgInfo = new SKImageInfo(_glArea.GetAllocatedWidth(), _glArea.GetAllocatedHeight()); _skSurface = SKSurface.Create(_ctx, false, imgInfo); - _controller.Canvas = _skSurface.Canvas; + if (_skSurface != null) + { + _controller.Canvas = _skSurface.Canvas; + } } /// diff --git a/NickvisionCavalier.GNOME/Views/MainWindow.cs b/NickvisionCavalier.GNOME/Views/MainWindow.cs index e165639..c6e2610 100644 --- a/NickvisionCavalier.GNOME/Views/MainWindow.cs +++ b/NickvisionCavalier.GNOME/Views/MainWindow.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.IO; using System.Text; +using System.Runtime.InteropServices; using static NickvisionCavalier.Shared.Helpers.Gettext; namespace NickvisionCavalier.GNOME.Views; @@ -12,8 +13,14 @@ namespace NickvisionCavalier.GNOME.Views; /// /// The MainWindow for the application /// -public class MainWindow : Adw.ApplicationWindow +public partial class MainWindow : Adw.ApplicationWindow { + [LibraryImport("libadwaita.so.1", StringMarshalling = StringMarshalling.Utf8)] + [return:MarshalAs(UnmanagedType.I1)] + private static partial bool g_main_context_iteration(nint context, [MarshalAs(UnmanagedType.I1)]bool mayBlock); + [LibraryImport("libadwaita.so.1", StringMarshalling = StringMarshalling.Utf8)] + private static partial nint g_main_context_default(); + [Gtk.Connect] private readonly Gtk.Overlay _overlay; [Gtk.Connect] private readonly Gtk.Revealer _headerRevealer; [Gtk.Connect] private readonly Adw.HeaderBar _header; @@ -28,12 +35,17 @@ private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.App //Window Settings _controller = controller; _application = application; + //Build UI + builder.Connect(this); SetDefaultSize((int)_controller.WindowWidth, (int)_controller.WindowHeight); SetTitle(_controller.AppInfo.ShortName); SetIconName(_controller.AppInfo.ID); - //Build UI - builder.Connect(this); _drawingView = new DrawingView(new DrawingViewController()); + _drawingView.OnFreeze += () => + { + g_main_context_iteration(g_main_context_default(), true); + QueueDraw(); + }; _overlay.SetChild(_drawingView); var prefController = _controller.CreatePreferencesViewController(); prefController.OnWindowSettingsChanged += UpdateWindowSettings; diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index 23b62fa..fb07b0d 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -1,6 +1,7 @@ using NickvisionCavalier.GNOME.Helpers; using NickvisionCavalier.Shared.Controllers; using NickvisionCavalier.Shared.Models; +using static NickvisionCavalier.Shared.Helpers.Gettext; namespace NickvisionCavalier.GNOME.Views; @@ -14,6 +15,7 @@ public partial class PreferencesDialog : Adw.PreferencesWindow [Gtk.Connect] private readonly Gtk.CheckButton _waveCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _barsCheckButton; + [Gtk.Connect] private readonly Adw.ComboRow _mirrorRow; [Gtk.Connect] private readonly Gtk.Scale _marginScale; [Gtk.Connect] private readonly Adw.ComboRow _directionRow; [Gtk.Connect] private readonly Adw.ActionRow _offsetRow; @@ -70,6 +72,31 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _barsCheckButton.SetActive(true); break; } + if (_controller.Stereo) + { + _mirrorRow.SetModel(Gtk.StringList.New(new string[] { _("Off"), _("Full"), _("Split Channels") })); + _mirrorRow.SetSelected((uint)_controller.Mirror); + } + else + { + _mirrorRow.SetModel(Gtk.StringList.New(new string[] { _("Off"), _("On") })); + if (_controller.Mirror == Mirror.SplitChannels) + { + _mirrorRow.SetSelected(1u); + } + else + { + _mirrorRow.SetSelected((uint)_controller.Mirror); + } + } + _mirrorRow.OnNotify += (sender, e) => + { + if (e.Pspec.GetName() == "selected") + { + _controller.Mirror = (Mirror)_mirrorRow.GetSelected(); + _controller.Save(); + } + }; _marginScale.SetValue((int)_controller.AreaMargin); _marginScale.OnValueChanged += (sender, e) => { @@ -187,7 +214,16 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _stereoButton.SetActive(_controller.Stereo); _stereoButton.OnToggled += (sender, e) => { - _controller.Stereo = _stereoButton.GetActive(); + if (_stereoButton.GetActive()) + { + _controller.Stereo = true; + _mirrorRow.SetModel(Gtk.StringList.New(new string[] { _("Off"), _("Full"), _("Split Channels") })); + } + else + { + _controller.Stereo = false; + _mirrorRow.SetModel(Gtk.StringList.New(new string[] { _("Off"), _("On") })); + } _controller.ChangeCavaSettings(); }; _monstercatSwitch.SetActive(_controller.Monstercat); diff --git a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs index a37b0c5..aa14447 100644 --- a/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs +++ b/NickvisionCavalier.Shared/Controllers/PreferencesViewController.cs @@ -224,6 +224,16 @@ public DrawingMode Mode set => Configuration.Current.Mode = value; } + /// + /// Mirror mode + /// + public Mirror Mirror + { + get => Configuration.Current.Mirror; + + set => Configuration.Current.Mirror = value; + } + /// /// Saves the configuration to disk /// diff --git a/NickvisionCavalier.Shared/Models/Configuration.cs b/NickvisionCavalier.Shared/Models/Configuration.cs index 1bba36c..9549b53 100644 --- a/NickvisionCavalier.Shared/Models/Configuration.cs +++ b/NickvisionCavalier.Shared/Models/Configuration.cs @@ -101,6 +101,10 @@ public class Configuration /// Active drawing mode /// public DrawingMode Mode { get; set; } + /// + /// Mirror mode + /// + public Mirror Mirror { get; set; } /// /// Occurs when the configuration is saved to disk @@ -138,6 +142,7 @@ public Configuration() Filling = true; LinesThickness = 15; Mode = DrawingMode.WaveBox; + Mirror = Mirror.Off; } /// diff --git a/NickvisionCavalier.Shared/Models/Mirror.cs b/NickvisionCavalier.Shared/Models/Mirror.cs new file mode 100644 index 0000000..54b590c --- /dev/null +++ b/NickvisionCavalier.Shared/Models/Mirror.cs @@ -0,0 +1,11 @@ +namespace NickvisionCavalier.Shared.Models; + +/// +/// Mirror mode +/// +public enum Mirror +{ + Off = 0, + Full, + SplitChannels +} \ No newline at end of file diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 955b38c..2c42c6c 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -1,9 +1,11 @@ using SkiaSharp; +using System.Linq; namespace NickvisionCavalier.Shared.Models; public class Renderer { + private Mirror _mirror => Configuration.Current.Mirror; private DrawingDirection _direction => Configuration.Current.Direction; private float _offset => Configuration.Current.ItemsOffset; private float _roundness => Configuration.Current.ItemsRoundness; @@ -33,94 +35,167 @@ public void Draw(float[] sample, float width, float height) switch (Configuration.Current.Mode) { case DrawingMode.WaveBox: - DrawWaveBox(sample, width, height, fgPaint); + if (_mirror == Mirror.Full) + { + DrawWaveBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawWaveBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else if (_mirror == Mirror.SplitChannels) + { + DrawWaveBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawWaveBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else + { + DrawWaveBox(sample, _direction, 0, 0, width, height, fgPaint); + } break; case DrawingMode.BarsBox: - DrawBarsBox(sample, width, height, fgPaint); + if (_mirror == Mirror.Full) + { + DrawBarsBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawBarsBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else if (_mirror == Mirror.SplitChannels) + { + DrawBarsBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawBarsBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else + { + DrawBarsBox(sample, _direction, 0, 0, width, height, fgPaint); + } break; } Canvas.Flush(); } - private void DrawWaveBox(float[] sample, float width, float height, SKPaint paint) + private DrawingDirection GetMirrorDirection() + { + return _direction switch + { + DrawingDirection.TopBottom => DrawingDirection.BottomTop, + DrawingDirection.BottomTop => DrawingDirection.TopBottom, + DrawingDirection.LeftRight => DrawingDirection.RightLeft, + _ => DrawingDirection.LeftRight + }; + } + + private float GetMirrorX(float width) + { + if (_direction == DrawingDirection.LeftRight || _direction == DrawingDirection.RightLeft) + { + return width / 2.0f; + } + return 0; + } + + private float GetMirrorY(float height) + { + if (_direction == DrawingDirection.TopBottom || _direction == DrawingDirection.BottomTop) + { + return height / 2.0f; + } + return 0; + } + + private float GetMirrorWidth(float width) + { + if (_direction == DrawingDirection.LeftRight || _direction == DrawingDirection.RightLeft) + { + return width / 2.0f; + } + return width; + } + + private float GetMirrorHeight(float height) + { + if (_direction == DrawingDirection.TopBottom || _direction == DrawingDirection.BottomTop) + { + return height / 2.0f; + } + return height; + } + + private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { - var step = (_direction < DrawingDirection.LeftRight ? width : height) / (sample.Length - 1); + var step = (direction < DrawingDirection.LeftRight ? width : height) / (sample.Length - 1); var path = new SKPath(); - switch (_direction) + switch (direction) { case DrawingDirection.TopBottom: - path.MoveTo(0, height * sample[0] - (_fill ? 0 : _thickness / 2)); + path.MoveTo(x, y + height * sample[0] - (_fill ? 0 : _thickness / 2)); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - step * (i + 0.5f), - height * sample[i] - (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - height * sample[i+1] - (_fill ? 0 : _thickness / 2), - step * (i + 1), - height * sample[i+1] - (_fill ? 0 : _thickness / 2)); + x + step * (i + 0.5f), + y + height * sample[i] - (_fill ? 0 : _thickness / 2), + x + step * (i + 0.5f), + y + height * sample[i+1] - (_fill ? 0 : _thickness / 2), + x + step * (i + 1), + y + height * sample[i+1] - (_fill ? 0 : _thickness / 2)); } if (_fill) { - path.LineTo(width, 0); - path.LineTo(0, 0); + path.LineTo(x + width, y); + path.LineTo(x, y); path.Close(); } break; case DrawingDirection.BottomTop: - path.MoveTo(0, height * (1 - sample[0]) + (_fill ? 0 : _thickness / 2)); + path.MoveTo(x, y + height * (1 - sample[0]) + (_fill ? 0 : _thickness / 2)); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - step * (i + 0.5f), - height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), - step * (i + 1), - height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2)); + x + step * (i + 0.5f), + y + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + x + step * (i + 0.5f), + y + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + x + step * (i + 1), + y + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2)); } if (_fill) { - path.LineTo(width, height); - path.LineTo(0, height); + path.LineTo(x + width, y + height); + path.LineTo(x, y + height); path.Close(); } break; case DrawingDirection.LeftRight: - path.MoveTo(width * sample[0] - (_fill ? 0 : _thickness / 2), 0); + path.MoveTo(x + width * sample[0] - (_fill ? 0 : _thickness / 2), y); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - width * sample[i] - (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - width * sample[i+1] - (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - width * sample[i+1] - (_fill ? 0 : _thickness / 2), - step * (i + 1)); + x + width * sample[i] - (_fill ? 0 : _thickness / 2), + y + step * (i + 0.5f), + x + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + y + step * (i + 0.5f), + x + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + y + step * (i + 1)); } if (_fill) { - path.LineTo(0, height); - path.LineTo(0, 0); + path.LineTo(x, y + height); + path.LineTo(x, y); path.Close(); } break; case DrawingDirection.RightLeft: - path.MoveTo(width * (1 - sample[0]) + (_fill ? 0 : _thickness / 2), 0); + path.MoveTo(x + width * (1 - sample[0]) + (_fill ? 0 : _thickness / 2), y); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), - step * (i + 0.5f), - width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), - step * (i + 1)); + x + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + y + step * (i + 0.5f), + x + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + y + step * (i + 0.5f), + x + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + y + step * (i + 1)); } if (_fill) { - path.LineTo(width, height); - path.LineTo(width, 0); + path.LineTo(x + width, y + height); + path.LineTo(x + width, y); path.Close(); } break; @@ -129,45 +204,45 @@ private void DrawWaveBox(float[] sample, float width, float height, SKPaint pain path.Dispose(); } - private void DrawBarsBox(float[] sample, float width, float height, SKPaint paint) + private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { - var step = (_direction < DrawingDirection.LeftRight ? width : height) / sample.Length; + var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; for (var i = 0; i < sample.Length; i++) { if (sample[i] == 0) { continue; } - switch (_direction) + switch (direction) { case DrawingDirection.TopBottom: Canvas.DrawRect( - step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - _fill ? 0 : _thickness / 2, + x + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + _fill ? y : y + _thickness / 2, step * (1 - _offset) - (_fill ? 0 : _thickness), height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.BottomTop: Canvas.DrawRect( - step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), - height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + x + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + y + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), step * (1 - _offset) - (_fill ? 0 : _thickness), height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.LeftRight: Canvas.DrawRect( - _fill ? 0 : _thickness / 2, - step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + _fill ? x : x + _thickness / 2, + y + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), width * sample[i] - (_fill ? 0 : _thickness), step * (1 - _offset) - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.RightLeft: Canvas.DrawRect( - width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + x + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), width * sample[i] - (_fill ? 0 : _thickness), step * (1 - _offset) - (_fill ? 0 : _thickness), paint); From d0136b8d5db7bdc92c3a5d60188a65c2dbe458e0 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 06:42:53 +0300 Subject: [PATCH 14/21] GNOME - Fix freezes Wrong threads again :D --- NickvisionCavalier.GNOME/Views/DrawingView.cs | 28 +++++++++---------- NickvisionCavalier.GNOME/Views/MainWindow.cs | 11 -------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/NickvisionCavalier.GNOME/Views/DrawingView.cs b/NickvisionCavalier.GNOME/Views/DrawingView.cs index 90caec0..822de31 100644 --- a/NickvisionCavalier.GNOME/Views/DrawingView.cs +++ b/NickvisionCavalier.GNOME/Views/DrawingView.cs @@ -11,10 +11,14 @@ namespace NickvisionCavalier.GNOME.Views; /// public partial class DrawingView : Gtk.Stack { + public delegate bool GSourceFunc(nint data); + [LibraryImport("libEGL.so.1", StringMarshalling = StringMarshalling.Utf8)] private static partial nint eglGetProcAddress(string name); [LibraryImport("libGL.so.1", StringMarshalling = StringMarshalling.Utf8)] private static partial void glClear(uint mask); + [LibraryImport("libadwaita-1.so.0", StringMarshalling = StringMarshalling.Utf8)] + private static partial void g_main_context_invoke(nint context, GSourceFunc function, nint data); [Gtk.Connect] private readonly Gtk.GLArea _glArea; @@ -22,19 +26,19 @@ public partial class DrawingView : Gtk.Stack private GRContext? _ctx; private SKSurface? _skSurface; private float[]? _sample; - private readonly System.Timers.Timer _antiFreezeTimer; - - public event Action? OnFreeze; + private readonly GSourceFunc _queueRender; private DrawingView(Gtk.Builder builder, DrawingViewController controller) : base(builder.GetPointer("_root"), false) { _controller = controller; - _antiFreezeTimer = new System.Timers.Timer(50); - _antiFreezeTimer.AutoReset = false; - _antiFreezeTimer.Elapsed += (sender, e) => + _queueRender = (x) => { - // GLArea can randomly freeze, stopping to react on QueueRender() - OnFreeze?.Invoke(); + if (GetVisibleChildName() != "gl") + { + SetVisibleChildName("gl"); + } + _glArea.QueueRender(); + return false; }; //Build UI builder.Connect(this); @@ -47,13 +51,8 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas _glArea.OnResize += (sender, e) => CreateSurface(); _controller.Cava.OutputReceived += (sender, sample) => { - if (GetVisibleChildName() != "gl") - { - SetVisibleChildName("gl"); - } - _antiFreezeTimer.Start(); _sample = sample; - _glArea.QueueRender(); + g_main_context_invoke(0, _queueRender, 0); }; _glArea.OnRender += OnRender; } @@ -85,7 +84,6 @@ private void CreateSurface() /// private bool OnRender(Gtk.GLArea sender, EventArgs e) { - _antiFreezeTimer.Stop(); if (_skSurface == null) { return false; diff --git a/NickvisionCavalier.GNOME/Views/MainWindow.cs b/NickvisionCavalier.GNOME/Views/MainWindow.cs index c6e2610..dd3db4b 100644 --- a/NickvisionCavalier.GNOME/Views/MainWindow.cs +++ b/NickvisionCavalier.GNOME/Views/MainWindow.cs @@ -15,12 +15,6 @@ namespace NickvisionCavalier.GNOME.Views; /// public partial class MainWindow : Adw.ApplicationWindow { - [LibraryImport("libadwaita.so.1", StringMarshalling = StringMarshalling.Utf8)] - [return:MarshalAs(UnmanagedType.I1)] - private static partial bool g_main_context_iteration(nint context, [MarshalAs(UnmanagedType.I1)]bool mayBlock); - [LibraryImport("libadwaita.so.1", StringMarshalling = StringMarshalling.Utf8)] - private static partial nint g_main_context_default(); - [Gtk.Connect] private readonly Gtk.Overlay _overlay; [Gtk.Connect] private readonly Gtk.Revealer _headerRevealer; [Gtk.Connect] private readonly Adw.HeaderBar _header; @@ -41,11 +35,6 @@ private MainWindow(Gtk.Builder builder, MainWindowController controller, Adw.App SetTitle(_controller.AppInfo.ShortName); SetIconName(_controller.AppInfo.ID); _drawingView = new DrawingView(new DrawingViewController()); - _drawingView.OnFreeze += () => - { - g_main_context_iteration(g_main_context_default(), true); - QueueDraw(); - }; _overlay.SetChild(_drawingView); var prefController = _controller.CreatePreferencesViewController(); prefController.OnWindowSettingsChanged += UpdateWindowSettings; From 15640386cef7735e7110302c841d4f817c657d29 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:10:09 +0300 Subject: [PATCH 15/21] GNOME - Particles Mode --- .../Blueprints/preferences_dialog.blp | 10 +++ .../Views/PreferencesDialog.cs | 13 ++++ NickvisionCavalier.Shared/Models/Renderer.cs | 77 +++++++++++++++++-- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 3e57f67..5a7abb5 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -24,6 +24,16 @@ Adw.PreferencesWindow _root { Gtk.CheckButton _waveCheckButton {} } + Adw.ActionRow { + title: _("Particles"); + activatable-widget: _particlesCheckButton; + + [prefix] + Gtk.CheckButton _particlesCheckButton { + group: _waveCheckButton; + } + } + Adw.ActionRow { title: _("Bars"); activatable-widget: _barsCheckButton; diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index fb07b0d..f2043e4 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -14,6 +14,7 @@ public partial class PreferencesDialog : Adw.PreferencesWindow private readonly Adw.Application _application; [Gtk.Connect] private readonly Gtk.CheckButton _waveCheckButton; + [Gtk.Connect] private readonly Gtk.CheckButton _particlesCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _barsCheckButton; [Gtk.Connect] private readonly Adw.ComboRow _mirrorRow; [Gtk.Connect] private readonly Gtk.Scale _marginScale; @@ -54,6 +55,15 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _roundnessRow.SetSensitive(false); } }; + _particlesCheckButton.OnToggled += (sender, e) => + { + if (_particlesCheckButton.GetActive()) + { + _controller.Mode = DrawingMode.ParticlesBox; + _offsetRow.SetSensitive(true); + _roundnessRow.SetSensitive(true); + } + }; _barsCheckButton.OnToggled += (sender, e) => { if (_barsCheckButton.GetActive()) @@ -68,6 +78,9 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control case DrawingMode.WaveBox: _waveCheckButton.SetActive(true); break; + case DrawingMode.ParticlesBox: + _particlesCheckButton.SetActive(true); + break; case DrawingMode.BarsBox: _barsCheckButton.SetActive(true); break; diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 2c42c6c..00f4926 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -50,6 +50,22 @@ public void Draw(float[] sample, float width, float height) DrawWaveBox(sample, _direction, 0, 0, width, height, fgPaint); } break; + case DrawingMode.ParticlesBox: + if (_mirror == Mirror.Full) + { + DrawParticlesBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawParticlesBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else if (_mirror == Mirror.SplitChannels) + { + DrawParticlesBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + DrawParticlesBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else + { + DrawParticlesBox(sample, _direction, 0, 0, width, height, fgPaint); + } + break; case DrawingMode.BarsBox: if (_mirror == Mirror.Full) { @@ -204,6 +220,51 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl path.Dispose(); } + private void DrawParticlesBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) + { + var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; + var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 11) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + var itemHeight = (direction < DrawingDirection.LeftRight ? height / 11 : step) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + for (var i = 0; i < sample.Length; i++) + { + switch (direction) + { + case DrawingDirection.TopBottom: + Canvas.DrawRoundRect( + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + y + height / 11 * 10 * sample[i] + height / 11 * _offset + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.BottomTop: + Canvas.DrawRoundRect( + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + y + height / 11 * 10 * (1 - sample[i]) + height / 11 * _offset + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.LeftRight: + Canvas.DrawRoundRect( + x + width / 11 * 10 * sample[i] + width / 11 * _offset + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.RightLeft: + Canvas.DrawRoundRect( + x + width / 11 * 10 * (1 - sample[i]) + width / 11 * _offset + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + } + } + } + private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; @@ -217,34 +278,34 @@ private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, fl { case DrawingDirection.TopBottom: Canvas.DrawRect( - x + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), _fill ? y : y + _thickness / 2, - step * (1 - _offset) - (_fill ? 0 : _thickness), + step * (1 - _offset * 2) - (_fill ? 0 : _thickness), height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.BottomTop: Canvas.DrawRect( - x + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), y + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - step * (1 - _offset) - (_fill ? 0 : _thickness), + step * (1 - _offset * 2) - (_fill ? 0 : _thickness), height * sample[i] - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.LeftRight: Canvas.DrawRect( _fill ? x : x + _thickness / 2, - y + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), width * sample[i] - (_fill ? 0 : _thickness), - step * (1 - _offset) - (_fill ? 0 : _thickness), + step * (1 - _offset * 2) - (_fill ? 0 : _thickness), paint); break; case DrawingDirection.RightLeft: Canvas.DrawRect( x + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset / 2) + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), width * sample[i] - (_fill ? 0 : _thickness), - step * (1 - _offset) - (_fill ? 0 : _thickness), + step * (1 - _offset * 2) - (_fill ? 0 : _thickness), paint); break; }; From f9555e7c5dcbbaee249046eeeae4ca3dd6e975a6 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:15:56 +0300 Subject: [PATCH 16/21] GNOME - Change Preferences window width --- NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 5a7abb5..13ca3d1 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -2,7 +2,7 @@ using Gtk 4.0; using Adw 1; Adw.PreferencesWindow _root { - default-width: 600; + default-width: 780; default-height: 500; modal: false; destroy-with-parent: true; From c08ef3ad01a59de20a8dc05c1e10ace09b0f1f08 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:12:39 +0300 Subject: [PATCH 17/21] GNOME - Levels mode --- .../Blueprints/preferences_dialog.blp | 10 ++ .../Views/PreferencesDialog.cs | 13 ++ NickvisionCavalier.Shared/Models/Renderer.cs | 120 +++++++++++------- 3 files changed, 94 insertions(+), 49 deletions(-) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 13ca3d1..42b8791 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -24,6 +24,16 @@ Adw.PreferencesWindow _root { Gtk.CheckButton _waveCheckButton {} } + Adw.ActionRow { + title: _("Levels"); + activatable-widget: _levelsCheckButton; + + [prefix] + Gtk.CheckButton _levelsCheckButton { + group: _waveCheckButton; + } + } + Adw.ActionRow { title: _("Particles"); activatable-widget: _particlesCheckButton; diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index f2043e4..266141a 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -14,6 +14,7 @@ public partial class PreferencesDialog : Adw.PreferencesWindow private readonly Adw.Application _application; [Gtk.Connect] private readonly Gtk.CheckButton _waveCheckButton; + [Gtk.Connect] private readonly Gtk.CheckButton _levelsCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _particlesCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _barsCheckButton; [Gtk.Connect] private readonly Adw.ComboRow _mirrorRow; @@ -55,6 +56,15 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _roundnessRow.SetSensitive(false); } }; + _levelsCheckButton.OnToggled += (sender, e) => + { + if (_levelsCheckButton.GetActive()) + { + _controller.Mode = DrawingMode.LevelsBox; + _offsetRow.SetSensitive(true); + _roundnessRow.SetSensitive(true); + } + }; _particlesCheckButton.OnToggled += (sender, e) => { if (_particlesCheckButton.GetActive()) @@ -78,6 +88,9 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control case DrawingMode.WaveBox: _waveCheckButton.SetActive(true); break; + case DrawingMode.LevelsBox: + _levelsCheckButton.SetActive(true); + break; case DrawingMode.ParticlesBox: _particlesCheckButton.SetActive(true); break; diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 00f4926..e2e48af 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -1,4 +1,5 @@ using SkiaSharp; +using System; using System.Linq; namespace NickvisionCavalier.Shared.Models; @@ -12,6 +13,9 @@ public class Renderer private bool _fill => Configuration.Current.Filling; private float _thickness => (float)Configuration.Current.LinesThickness; + private delegate void DrawFunc(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint); + private DrawFunc? _drawFunc; + public SKCanvas? Canvas { get; set; } public Renderer() @@ -32,56 +36,26 @@ public void Draw(float[] sample, float width, float height) StrokeWidth = _thickness, Color = SKColors.Blue }; - switch (Configuration.Current.Mode) + _drawFunc = Configuration.Current.Mode switch { - case DrawingMode.WaveBox: - if (_mirror == Mirror.Full) - { - DrawWaveBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawWaveBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else if (_mirror == Mirror.SplitChannels) - { - DrawWaveBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawWaveBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else - { - DrawWaveBox(sample, _direction, 0, 0, width, height, fgPaint); - } - break; - case DrawingMode.ParticlesBox: - if (_mirror == Mirror.Full) - { - DrawParticlesBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawParticlesBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else if (_mirror == Mirror.SplitChannels) - { - DrawParticlesBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawParticlesBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else - { - DrawParticlesBox(sample, _direction, 0, 0, width, height, fgPaint); - } - break; - case DrawingMode.BarsBox: - if (_mirror == Mirror.Full) - { - DrawBarsBox(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawBarsBox(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else if (_mirror == Mirror.SplitChannels) - { - DrawBarsBox(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - DrawBarsBox(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); - } - else - { - DrawBarsBox(sample, _direction, 0, 0, width, height, fgPaint); - } - break; + DrawingMode.LevelsBox => DrawLevelsBox, + DrawingMode.ParticlesBox => DrawParticlesBox, + DrawingMode.BarsBox => DrawBarsBox, + _ => DrawWaveBox, + }; + if (_mirror == Mirror.Full) + { + _drawFunc(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + _drawFunc(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else if (_mirror == Mirror.SplitChannels) + { + _drawFunc(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + _drawFunc(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + } + else + { + _drawFunc(sample, _direction, 0, 0, width, height, fgPaint); } Canvas.Flush(); } @@ -220,6 +194,54 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl path.Dispose(); } + private void DrawLevelsBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) + { + var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; + var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 10) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + var itemHeight = (direction < DrawingDirection.LeftRight ? height / 10 : step) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + for (var i = 0; i < sample.Length; i++) + { + for (var j = 0; j < Math.Floor(sample[i] * 10); j++) + { + switch (direction) + { + case DrawingDirection.TopBottom: + Canvas.DrawRoundRect( + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + y + height / 10 * j + height / 10 * _offset + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.BottomTop: + Canvas.DrawRoundRect( + x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + y + height / 10 * (9 - j) + height / 10 * _offset + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.LeftRight: + Canvas.DrawRoundRect( + x + width / 10 * j + width / 10 * _offset + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + case DrawingDirection.RightLeft: + Canvas.DrawRoundRect( + x + width / 10 * (9 - j) + width / 10 * _offset + (_fill ? 0 : _thickness / 2), + y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + itemWidth, itemHeight, + itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + paint); + break; + } + } + } + } + private void DrawParticlesBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; From 7edb701dc9024f4a170e9e4b74103c52513998de Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:51:47 +0300 Subject: [PATCH 18/21] GNOME - Spine mode --- .../Blueprints/preferences_dialog.blp | 10 ++++++ .../Views/PreferencesDialog.cs | 13 +++++++ NickvisionCavalier.Shared/Models/Renderer.cs | 35 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp index 42b8791..1b183bf 100644 --- a/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp +++ b/NickvisionCavalier.GNOME/Blueprints/preferences_dialog.blp @@ -53,6 +53,16 @@ Adw.PreferencesWindow _root { group: _waveCheckButton; } } + + Adw.ActionRow { + title: _("Spine"); + activatable-widget: _spineCheckButton; + + [prefix] + Gtk.CheckButton _spineCheckButton { + group: _waveCheckButton; + } + } } Adw.PreferencesGroup { diff --git a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs index 266141a..9284007 100644 --- a/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs +++ b/NickvisionCavalier.GNOME/Views/PreferencesDialog.cs @@ -17,6 +17,7 @@ public partial class PreferencesDialog : Adw.PreferencesWindow [Gtk.Connect] private readonly Gtk.CheckButton _levelsCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _particlesCheckButton; [Gtk.Connect] private readonly Gtk.CheckButton _barsCheckButton; + [Gtk.Connect] private readonly Gtk.CheckButton _spineCheckButton; [Gtk.Connect] private readonly Adw.ComboRow _mirrorRow; [Gtk.Connect] private readonly Gtk.Scale _marginScale; [Gtk.Connect] private readonly Adw.ComboRow _directionRow; @@ -83,6 +84,15 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control _roundnessRow.SetSensitive(false); } }; + _spineCheckButton.OnToggled += (sender, e) => + { + if (_spineCheckButton.GetActive()) + { + _controller.Mode = DrawingMode.SpineBox; + _offsetRow.SetSensitive(true); + _roundnessRow.SetSensitive(true); + } + }; switch (_controller.Mode) { case DrawingMode.WaveBox: @@ -97,6 +107,9 @@ private PreferencesDialog(Gtk.Builder builder, PreferencesViewController control case DrawingMode.BarsBox: _barsCheckButton.SetActive(true); break; + case DrawingMode.SpineBox: + _spineCheckButton.SetActive(true); + break; } if (_controller.Stereo) { diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index e2e48af..c8ec7b8 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -41,6 +41,7 @@ public void Draw(float[] sample, float width, float height) DrawingMode.LevelsBox => DrawLevelsBox, DrawingMode.ParticlesBox => DrawParticlesBox, DrawingMode.BarsBox => DrawBarsBox, + DrawingMode.SpineBox => DrawSpineBox, _ => DrawWaveBox, }; if (_mirror == Mirror.Full) @@ -333,4 +334,38 @@ private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, fl }; } } + + private void DrawSpineBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) + { + var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; + var itemSize = step * (1 - _offset * 2) - (_fill ? 0 : _thickness); + for (var i = 0; i < sample.Length; i++) + { + if (sample[i] == 0) + { + continue; + } + switch (direction) + { + case DrawingDirection.TopBottom: + case DrawingDirection.BottomTop: + Canvas.DrawRoundRect( + x + step * (i + 0.5f) + (1 - itemSize * sample[i]) / 2, + y + height / 2 - itemSize * sample[i] / 2, + itemSize * sample[i], itemSize * sample[i], + itemSize * sample[i] / 2 * _roundness, itemSize * sample[i] / 2 * _roundness, + paint); + break; + case DrawingDirection.LeftRight: + case DrawingDirection.RightLeft: + Canvas.DrawRoundRect( + x + width / 2 - itemSize * sample[i] / 2, + y + step * (i + 0.5f) + (1 - itemSize * sample[i]) / 2, + itemSize * sample[i], itemSize * sample[i], + itemSize * sample[i] / 2 * _roundness, itemSize * sample[i] / 2 * _roundness, + paint); + break; + } + } + } } From 195ff0fa39dca6e63bc7a0730510a0dac4532700 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 13:52:11 +0300 Subject: [PATCH 19/21] Cleanup --- NickvisionCavalier.GNOME/Views/MainWindow.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NickvisionCavalier.GNOME/Views/MainWindow.cs b/NickvisionCavalier.GNOME/Views/MainWindow.cs index dd3db4b..a75e3e5 100644 --- a/NickvisionCavalier.GNOME/Views/MainWindow.cs +++ b/NickvisionCavalier.GNOME/Views/MainWindow.cs @@ -5,7 +5,6 @@ using System.Globalization; using System.IO; using System.Text; -using System.Runtime.InteropServices; using static NickvisionCavalier.Shared.Helpers.Gettext; namespace NickvisionCavalier.GNOME.Views; @@ -13,7 +12,7 @@ namespace NickvisionCavalier.GNOME.Views; /// /// The MainWindow for the application /// -public partial class MainWindow : Adw.ApplicationWindow +public class MainWindow : Adw.ApplicationWindow { [Gtk.Connect] private readonly Gtk.Overlay _overlay; [Gtk.Connect] private readonly Gtk.Revealer _headerRevealer; From 1dc5f7afd23233b1aa0d8d6bac392cfe59cb4c78 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 16:32:42 +0300 Subject: [PATCH 20/21] Shared - Small fixes --- NickvisionCavalier.Shared/Models/DrawingMode.cs | 6 +++++- NickvisionCavalier.Shared/Models/Renderer.cs | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/NickvisionCavalier.Shared/Models/DrawingMode.cs b/NickvisionCavalier.Shared/Models/DrawingMode.cs index 76261a9..1150178 100644 --- a/NickvisionCavalier.Shared/Models/DrawingMode.cs +++ b/NickvisionCavalier.Shared/Models/DrawingMode.cs @@ -1,6 +1,10 @@ namespace NickvisionCavalier.Shared.Models; -public enum DrawingMode { +/// +/// Active drawing mode +/// +public enum DrawingMode +{ WaveBox = 0, LevelsBox, ParticlesBox, diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index c8ec7b8..3fde373 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -111,7 +111,7 @@ private float GetMirrorHeight(float height) private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / (sample.Length - 1); - var path = new SKPath(); + using var path = new SKPath(); switch (direction) { case DrawingDirection.TopBottom: @@ -192,7 +192,6 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl break; } Canvas.DrawPath(path, paint); - path.Dispose(); } private void DrawLevelsBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) From e622f6b427a0cc3d6527b86d76a1050475d50d68 Mon Sep 17 00:00:00 2001 From: Fyodor Sobolev <117388856+fsobolev@users.noreply.github.com> Date: Tue, 27 Jun 2023 16:48:22 +0300 Subject: [PATCH 21/21] Shared - Use config values directly in renderer --- NickvisionCavalier.Shared/Models/Renderer.cs | 165 +++++++++---------- 1 file changed, 79 insertions(+), 86 deletions(-) diff --git a/NickvisionCavalier.Shared/Models/Renderer.cs b/NickvisionCavalier.Shared/Models/Renderer.cs index 3fde373..de69852 100644 --- a/NickvisionCavalier.Shared/Models/Renderer.cs +++ b/NickvisionCavalier.Shared/Models/Renderer.cs @@ -6,13 +6,6 @@ namespace NickvisionCavalier.Shared.Models; public class Renderer { - private Mirror _mirror => Configuration.Current.Mirror; - private DrawingDirection _direction => Configuration.Current.Direction; - private float _offset => Configuration.Current.ItemsOffset; - private float _roundness => Configuration.Current.ItemsRoundness; - private bool _fill => Configuration.Current.Filling; - private float _thickness => (float)Configuration.Current.LinesThickness; - private delegate void DrawFunc(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint); private DrawFunc? _drawFunc; @@ -32,8 +25,8 @@ public void Draw(float[] sample, float width, float height) Canvas.Clear(); var fgPaint = new SKPaint { - Style = _fill ? SKPaintStyle.Fill : SKPaintStyle.Stroke, - StrokeWidth = _thickness, + Style = Configuration.Current.Filling ? SKPaintStyle.Fill : SKPaintStyle.Stroke, + StrokeWidth = Configuration.Current.LinesThickness, Color = SKColors.Blue }; _drawFunc = Configuration.Current.Mode switch @@ -44,26 +37,26 @@ public void Draw(float[] sample, float width, float height) DrawingMode.SpineBox => DrawSpineBox, _ => DrawWaveBox, }; - if (_mirror == Mirror.Full) + if (Configuration.Current.Mirror == Mirror.Full) { - _drawFunc(sample, _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + _drawFunc(sample, Configuration.Current.Direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); _drawFunc(sample, GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); } - else if (_mirror == Mirror.SplitChannels) + else if (Configuration.Current.Mirror == Mirror.SplitChannels) { - _drawFunc(sample.Take(sample.Length / 2).ToArray(), _direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); + _drawFunc(sample.Take(sample.Length / 2).ToArray(), Configuration.Current.Direction, 0, 0, GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); _drawFunc(sample.Skip(sample.Length / 2).Reverse().ToArray(), GetMirrorDirection(), GetMirrorX(width), GetMirrorY(height), GetMirrorWidth(width), GetMirrorHeight(height), fgPaint); } else { - _drawFunc(sample, _direction, 0, 0, width, height, fgPaint); + _drawFunc(sample, Configuration.Current.Direction, 0, 0, width, height, fgPaint); } Canvas.Flush(); } private DrawingDirection GetMirrorDirection() { - return _direction switch + return Configuration.Current.Direction switch { DrawingDirection.TopBottom => DrawingDirection.BottomTop, DrawingDirection.BottomTop => DrawingDirection.TopBottom, @@ -74,7 +67,7 @@ private DrawingDirection GetMirrorDirection() private float GetMirrorX(float width) { - if (_direction == DrawingDirection.LeftRight || _direction == DrawingDirection.RightLeft) + if (Configuration.Current.Direction == DrawingDirection.LeftRight || Configuration.Current.Direction == DrawingDirection.RightLeft) { return width / 2.0f; } @@ -83,7 +76,7 @@ private float GetMirrorX(float width) private float GetMirrorY(float height) { - if (_direction == DrawingDirection.TopBottom || _direction == DrawingDirection.BottomTop) + if (Configuration.Current.Direction == DrawingDirection.TopBottom || Configuration.Current.Direction == DrawingDirection.BottomTop) { return height / 2.0f; } @@ -92,7 +85,7 @@ private float GetMirrorY(float height) private float GetMirrorWidth(float width) { - if (_direction == DrawingDirection.LeftRight || _direction == DrawingDirection.RightLeft) + if (Configuration.Current.Direction == DrawingDirection.LeftRight || Configuration.Current.Direction == DrawingDirection.RightLeft) { return width / 2.0f; } @@ -101,7 +94,7 @@ private float GetMirrorWidth(float width) private float GetMirrorHeight(float height) { - if (_direction == DrawingDirection.TopBottom || _direction == DrawingDirection.BottomTop) + if (Configuration.Current.Direction == DrawingDirection.TopBottom || Configuration.Current.Direction == DrawingDirection.BottomTop) { return height / 2.0f; } @@ -115,18 +108,18 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl switch (direction) { case DrawingDirection.TopBottom: - path.MoveTo(x, y + height * sample[0] - (_fill ? 0 : _thickness / 2)); + path.MoveTo(x, y + height * sample[0] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2)); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( x + step * (i + 0.5f), - y + height * sample[i] - (_fill ? 0 : _thickness / 2), + y + height * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), x + step * (i + 0.5f), - y + height * sample[i+1] - (_fill ? 0 : _thickness / 2), + y + height * sample[i+1] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), x + step * (i + 1), - y + height * sample[i+1] - (_fill ? 0 : _thickness / 2)); + y + height * sample[i+1] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2)); } - if (_fill) + if (Configuration.Current.Filling) { path.LineTo(x + width, y); path.LineTo(x, y); @@ -134,18 +127,18 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl } break; case DrawingDirection.BottomTop: - path.MoveTo(x, y + height * (1 - sample[0]) + (_fill ? 0 : _thickness / 2)); + path.MoveTo(x, y + height * (1 - sample[0]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2)); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( x + step * (i + 0.5f), - y + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + y + height * (1 - sample[i]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), x + step * (i + 0.5f), - y + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + y + height * (1 - sample[i+1]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), x + step * (i + 1), - y + height * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2)); + y + height * (1 - sample[i+1]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2)); } - if (_fill) + if (Configuration.Current.Filling) { path.LineTo(x + width, y + height); path.LineTo(x, y + height); @@ -153,18 +146,18 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl } break; case DrawingDirection.LeftRight: - path.MoveTo(x + width * sample[0] - (_fill ? 0 : _thickness / 2), y); + path.MoveTo(x + width * sample[0] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - x + width * sample[i] - (_fill ? 0 : _thickness / 2), + x + width * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 0.5f), - x + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + x + width * sample[i+1] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 0.5f), - x + width * sample[i+1] - (_fill ? 0 : _thickness / 2), + x + width * sample[i+1] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 1)); } - if (_fill) + if (Configuration.Current.Filling) { path.LineTo(x, y + height); path.LineTo(x, y); @@ -172,18 +165,18 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl } break; case DrawingDirection.RightLeft: - path.MoveTo(x + width * (1 - sample[0]) + (_fill ? 0 : _thickness / 2), y); + path.MoveTo(x + width * (1 - sample[0]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y); for (var i = 0; i < sample.Length - 1; i++) { path.CubicTo( - x + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), + x + width * (1 - sample[i]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 0.5f), - x + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + x + width * (1 - sample[i+1]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 0.5f), - x + width * (1 - sample[i+1]) + (_fill ? 0 : _thickness / 2), + x + width * (1 - sample[i+1]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), y + step * (i + 1)); } - if (_fill) + if (Configuration.Current.Filling) { path.LineTo(x + width, y + height); path.LineTo(x + width, y); @@ -197,8 +190,8 @@ private void DrawWaveBox(float[] sample, DrawingDirection direction, float x, fl private void DrawLevelsBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; - var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 10) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); - var itemHeight = (direction < DrawingDirection.LeftRight ? height / 10 : step) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 10) * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2); + var itemHeight = (direction < DrawingDirection.LeftRight ? height / 10 : step) * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2); for (var i = 0; i < sample.Length; i++) { for (var j = 0; j < Math.Floor(sample[i] * 10); j++) @@ -207,34 +200,34 @@ private void DrawLevelsBox(float[] sample, DrawingDirection direction, float x, { case DrawingDirection.TopBottom: Canvas.DrawRoundRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - y + height / 10 * j + height / 10 * _offset + (_fill ? 0 : _thickness / 2), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + height / 10 * j + height / 10 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.BottomTop: Canvas.DrawRoundRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - y + height / 10 * (9 - j) + height / 10 * _offset + (_fill ? 0 : _thickness / 2), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + height / 10 * (9 - j) + height / 10 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.LeftRight: Canvas.DrawRoundRect( - x + width / 10 * j + width / 10 * _offset + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + x + width / 10 * j + width / 10 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.RightLeft: Canvas.DrawRoundRect( - x + width / 10 * (9 - j) + width / 10 * _offset + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + x + width / 10 * (9 - j) + width / 10 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; } @@ -245,42 +238,42 @@ private void DrawLevelsBox(float[] sample, DrawingDirection direction, float x, private void DrawParticlesBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; - var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 11) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); - var itemHeight = (direction < DrawingDirection.LeftRight ? height / 11 : step) * (1 - _offset * 2) - (_fill ? 0 : _thickness / 2); + var itemWidth = (direction < DrawingDirection.LeftRight ? step : width / 11) * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2); + var itemHeight = (direction < DrawingDirection.LeftRight ? height / 11 : step) * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2); for (var i = 0; i < sample.Length; i++) { switch (direction) { case DrawingDirection.TopBottom: Canvas.DrawRoundRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - y + height / 11 * 10 * sample[i] + height / 11 * _offset + (_fill ? 0 : _thickness / 2), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + height / 11 * 10 * sample[i] + height / 11 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.BottomTop: Canvas.DrawRoundRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - y + height / 11 * 10 * (1 - sample[i]) + height / 11 * _offset + (_fill ? 0 : _thickness / 2), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + height / 11 * 10 * (1 - sample[i]) + height / 11 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.LeftRight: Canvas.DrawRoundRect( - x + width / 11 * 10 * sample[i] + width / 11 * _offset + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + x + width / 11 * 10 * sample[i] + width / 11 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.RightLeft: Canvas.DrawRoundRect( - x + width / 11 * 10 * (1 - sample[i]) + width / 11 * _offset + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), + x + width / 11 * 10 * (1 - sample[i]) + width / 11 * Configuration.Current.ItemsOffset + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), itemWidth, itemHeight, - itemWidth / 2 * _roundness, itemHeight / 2 * _roundness, + itemWidth / 2 * Configuration.Current.ItemsRoundness, itemHeight / 2 * Configuration.Current.ItemsRoundness, paint); break; } @@ -300,34 +293,34 @@ private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, fl { case DrawingDirection.TopBottom: Canvas.DrawRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - _fill ? y : y + _thickness / 2, - step * (1 - _offset * 2) - (_fill ? 0 : _thickness), - height * sample[i] - (_fill ? 0 : _thickness), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + Configuration.Current.Filling ? y : y + Configuration.Current.LinesThickness / 2, + step * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), + height * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), paint); break; case DrawingDirection.BottomTop: Canvas.DrawRect( - x + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - y + height * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - step * (1 - _offset * 2) - (_fill ? 0 : _thickness), - height * sample[i] - (_fill ? 0 : _thickness), + x + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + height * (1 - sample[i]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + step * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), + height * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), paint); break; case DrawingDirection.LeftRight: Canvas.DrawRect( - _fill ? x : x + _thickness / 2, - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - width * sample[i] - (_fill ? 0 : _thickness), - step * (1 - _offset * 2) - (_fill ? 0 : _thickness), + Configuration.Current.Filling ? x : x + Configuration.Current.LinesThickness / 2, + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + width * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), + step * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), paint); break; case DrawingDirection.RightLeft: Canvas.DrawRect( - x + width * (1 - sample[i]) + (_fill ? 0 : _thickness / 2), - y + step * (i + _offset) + (_fill ? 0 : _thickness / 2), - width * sample[i] - (_fill ? 0 : _thickness), - step * (1 - _offset * 2) - (_fill ? 0 : _thickness), + x + width * (1 - sample[i]) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + y + step * (i + Configuration.Current.ItemsOffset) + (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness / 2), + width * sample[i] - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), + step * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness), paint); break; }; @@ -337,7 +330,7 @@ private void DrawBarsBox(float[] sample, DrawingDirection direction, float x, fl private void DrawSpineBox(float[] sample, DrawingDirection direction, float x, float y, float width, float height, SKPaint paint) { var step = (direction < DrawingDirection.LeftRight ? width : height) / sample.Length; - var itemSize = step * (1 - _offset * 2) - (_fill ? 0 : _thickness); + var itemSize = step * (1 - Configuration.Current.ItemsOffset * 2) - (Configuration.Current.Filling ? 0 : Configuration.Current.LinesThickness); for (var i = 0; i < sample.Length; i++) { if (sample[i] == 0) @@ -352,7 +345,7 @@ private void DrawSpineBox(float[] sample, DrawingDirection direction, float x, f x + step * (i + 0.5f) + (1 - itemSize * sample[i]) / 2, y + height / 2 - itemSize * sample[i] / 2, itemSize * sample[i], itemSize * sample[i], - itemSize * sample[i] / 2 * _roundness, itemSize * sample[i] / 2 * _roundness, + itemSize * sample[i] / 2 * Configuration.Current.ItemsRoundness, itemSize * sample[i] / 2 * Configuration.Current.ItemsRoundness, paint); break; case DrawingDirection.LeftRight: @@ -361,7 +354,7 @@ private void DrawSpineBox(float[] sample, DrawingDirection direction, float x, f x + width / 2 - itemSize * sample[i] / 2, y + step * (i + 0.5f) + (1 - itemSize * sample[i]) / 2, itemSize * sample[i], itemSize * sample[i], - itemSize * sample[i] / 2 * _roundness, itemSize * sample[i] / 2 * _roundness, + itemSize * sample[i] / 2 * Configuration.Current.ItemsRoundness, itemSize * sample[i] / 2 * Configuration.Current.ItemsRoundness, paint); break; }