|
|
@@ -7,274 +7,108 @@ using System.Globalization;
|
|
|
|
|
|
namespace YZWater.Avalonia.Controls;
|
|
|
|
|
|
-/// <summary>
|
|
|
-/// 娉垫帶浠 - 妯℃嫙 HslPumpOne锛堜紭鍖栫増锛
|
|
|
-/// </summary>
|
|
|
public class PumpControl : Control
|
|
|
{
|
|
|
public static readonly StyledProperty<bool> IsRunningProperty =
|
|
|
AvaloniaProperty.Register<PumpControl, bool>(nameof(IsRunning), false);
|
|
|
-
|
|
|
public static readonly StyledProperty<double> SpeedProperty =
|
|
|
AvaloniaProperty.Register<PumpControl, double>(nameof(Speed), 0.0);
|
|
|
-
|
|
|
public static readonly StyledProperty<double> FrequencyProperty =
|
|
|
AvaloniaProperty.Register<PumpControl, double>(nameof(Frequency), 50.0);
|
|
|
-
|
|
|
public static readonly StyledProperty<string> TextProperty =
|
|
|
AvaloniaProperty.Register<PumpControl, string>(nameof(Text), string.Empty);
|
|
|
-
|
|
|
public static readonly StyledProperty<IBrush> RunningColorProperty =
|
|
|
- AvaloniaProperty.Register<PumpControl, IBrush>(nameof(RunningColor), new SolidColorBrush(Color.Parse("#4CAF50")));
|
|
|
-
|
|
|
+ AvaloniaProperty.Register<PumpControl, IBrush>(nameof(RunningColor));
|
|
|
public static readonly StyledProperty<IBrush> StoppedColorProperty =
|
|
|
- AvaloniaProperty.Register<PumpControl, IBrush>(nameof(StoppedColor), new SolidColorBrush(Color.Parse("#607D8B")));
|
|
|
-
|
|
|
- public static readonly StyledProperty<IBrush> FaultColorProperty =
|
|
|
- AvaloniaProperty.Register<PumpControl, IBrush>(nameof(FaultColor), new SolidColorBrush(Color.Parse("#F44336")));
|
|
|
-
|
|
|
- public bool IsRunning
|
|
|
- {
|
|
|
- get => GetValue(IsRunningProperty);
|
|
|
- set => SetValue(IsRunningProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
- public double Speed
|
|
|
- {
|
|
|
- get => GetValue(SpeedProperty);
|
|
|
- set => SetValue(SpeedProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
- public double Frequency
|
|
|
- {
|
|
|
- get => GetValue(FrequencyProperty);
|
|
|
- set => SetValue(FrequencyProperty, value);
|
|
|
- }
|
|
|
+ AvaloniaProperty.Register<PumpControl, IBrush>(nameof(StoppedColor));
|
|
|
|
|
|
- public string Text
|
|
|
- {
|
|
|
- get => GetValue(TextProperty);
|
|
|
- set => SetValue(TextProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
- public IBrush RunningColor
|
|
|
- {
|
|
|
- get => GetValue(RunningColorProperty);
|
|
|
- set => SetValue(RunningColorProperty, value);
|
|
|
- }
|
|
|
+ public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); }
|
|
|
+ public double Speed { get => GetValue(SpeedProperty); set => SetValue(SpeedProperty, value); }
|
|
|
+ public double Frequency { get => GetValue(FrequencyProperty); set => SetValue(FrequencyProperty, value); }
|
|
|
+ public string Text { get => GetValue(TextProperty); set => SetValue(TextProperty, value); }
|
|
|
+ public IBrush RunningColor { get => GetValue(RunningColorProperty); set => SetValue(RunningColorProperty, value); }
|
|
|
+ public IBrush StoppedColor { get => GetValue(StoppedColorProperty); set => SetValue(StoppedColorProperty, value); }
|
|
|
|
|
|
- public IBrush StoppedColor
|
|
|
- {
|
|
|
- get => GetValue(StoppedColorProperty);
|
|
|
- set => SetValue(StoppedColorProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
- public IBrush FaultColor
|
|
|
- {
|
|
|
- get => GetValue(FaultColorProperty);
|
|
|
- set => SetValue(FaultColorProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
- private double _rotationAngle = 0;
|
|
|
- private IDisposable? _timerSubscription;
|
|
|
+ private double _rotationAngle;
|
|
|
+ private IDisposable? _timer;
|
|
|
|
|
|
static PumpControl()
|
|
|
{
|
|
|
- AffectsRender<PumpControl>(IsRunningProperty, SpeedProperty, FrequencyProperty,
|
|
|
- TextProperty, RunningColorProperty, StoppedColorProperty, FaultColorProperty);
|
|
|
- }
|
|
|
-
|
|
|
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
|
|
- {
|
|
|
- base.OnAttachedToVisualTree(e);
|
|
|
- if (IsRunning)
|
|
|
- {
|
|
|
- StartAnimation();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
|
|
- {
|
|
|
- base.OnDetachedFromVisualTree(e);
|
|
|
- StopAnimation();
|
|
|
+ AffectsRender<PumpControl>(IsRunningProperty, SpeedProperty, FrequencyProperty, TextProperty, RunningColorProperty, StoppedColorProperty);
|
|
|
}
|
|
|
|
|
|
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); if (IsRunning) StartAnim(); }
|
|
|
+ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); StopAnim(); }
|
|
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
|
|
{
|
|
|
base.OnPropertyChanged(change);
|
|
|
- if (change.Property == IsRunningProperty)
|
|
|
- {
|
|
|
- if (IsRunning)
|
|
|
- {
|
|
|
- StartAnimation();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- StopAnimation();
|
|
|
- _rotationAngle = 0;
|
|
|
- }
|
|
|
- InvalidateVisual();
|
|
|
- }
|
|
|
+ if (change.Property == IsRunningProperty) { if (IsRunning) StartAnim(); else { StopAnim(); _rotationAngle = 0; } }
|
|
|
}
|
|
|
|
|
|
- private void StartAnimation()
|
|
|
- {
|
|
|
- StopAnimation();
|
|
|
- _timerSubscription = DispatcherTimer.Run(() =>
|
|
|
- {
|
|
|
- _rotationAngle += Frequency / 20.0;
|
|
|
- if (_rotationAngle >= 360) _rotationAngle -= 360;
|
|
|
- InvalidateVisual();
|
|
|
- return true;
|
|
|
- }, TimeSpan.FromMilliseconds(30));
|
|
|
- }
|
|
|
-
|
|
|
- private void StopAnimation()
|
|
|
- {
|
|
|
- _timerSubscription?.Dispose();
|
|
|
- _timerSubscription = null;
|
|
|
- }
|
|
|
+ private void StartAnim() { StopAnim(); _timer = DispatcherTimer.Run(() => { _rotationAngle += Frequency / 20; if (_rotationAngle >= 360) _rotationAngle -= 360; InvalidateVisual(); return true; }, TimeSpan.FromMilliseconds(30)); }
|
|
|
+ private void StopAnim() { _timer?.Dispose(); _timer = null; }
|
|
|
|
|
|
public override void Render(DrawingContext context)
|
|
|
{
|
|
|
base.Render(context);
|
|
|
-
|
|
|
var bounds = new Rect(Bounds.Size);
|
|
|
- var centerX = bounds.Width / 2;
|
|
|
- var centerY = bounds.Height / 2 - 5;
|
|
|
+ var cx = bounds.Width / 2;
|
|
|
+ var cy = bounds.Height / 2 - 5;
|
|
|
var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 15;
|
|
|
var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
|
|
|
|
|
|
- // 纭畾鐘舵侀鑹
|
|
|
- var statusColor = IsRunning ? RunningColor : StoppedColor;
|
|
|
- var statusBrush = statusColor as SolidColorBrush ?? new SolidColorBrush(Colors.Gray);
|
|
|
+ var statusColor = (IsRunning ? RunningColor : StoppedColor) ?? (IsRunning ? ThemeHelper.Success() : ThemeHelper.TextDisabled());
|
|
|
+ var statusBrush = statusColor as SolidColorBrush ?? ThemeHelper.Success();
|
|
|
|
|
|
- // 缁樺埗澶栧湀鍙戝厜鏁堟灉锛堣繍琛屾椂锛
|
|
|
+ // 鍙戝厜
|
|
|
if (IsRunning)
|
|
|
- {
|
|
|
- var glowBrush = new SolidColorBrush(statusBrush.Color, 0.2);
|
|
|
- context.DrawEllipse(glowBrush, null, new Rect(
|
|
|
- centerX - radius - 8,
|
|
|
- centerY - radius - 8,
|
|
|
- (radius + 8) * 2,
|
|
|
- (radius + 8) * 2));
|
|
|
- }
|
|
|
-
|
|
|
- // 缁樺埗澶栧3
|
|
|
- var outerPen = new Pen(new SolidColorBrush(Color.Parse("#455A64")), 3);
|
|
|
- context.DrawEllipse(null, outerPen, new Rect(
|
|
|
- centerX - radius,
|
|
|
- centerY - radius,
|
|
|
- radius * 2,
|
|
|
- radius * 2));
|
|
|
+ context.DrawEllipse(new SolidColorBrush((statusBrush as SolidColorBrush)?.Color ?? Colors.Gray, 0.2), null, new Rect(cx - radius - 8, cy - radius - 8, (radius + 8) * 2, (radius + 8) * 2));
|
|
|
|
|
|
- // 缁樺埗鍐呴儴鑳屾櫙
|
|
|
- var innerBg = new SolidColorBrush(Color.Parse("#1E272E"));
|
|
|
- context.DrawEllipse(innerBg, null, new Rect(
|
|
|
- centerX - radius + 3,
|
|
|
- centerY - radius + 3,
|
|
|
- (radius - 3) * 2,
|
|
|
- (radius - 3) * 2));
|
|
|
+ // 澶栧3
|
|
|
+ context.DrawEllipse(null, new Pen(ThemeHelper.Border(), 3), new Rect(cx - radius, cy - radius, radius * 2, radius * 2));
|
|
|
+ context.DrawEllipse(ThemeHelper.PanelBg(), null, new Rect(cx - radius + 3, cy - radius + 3, (radius - 3) * 2, (radius - 3) * 2));
|
|
|
|
|
|
- // 缁樺埗娉鍙剁墖
|
|
|
+ // 鍙剁墖
|
|
|
var bladeCount = 6;
|
|
|
- var bladeLength = radius * 0.65;
|
|
|
- var bladeWidth = radius * 0.18;
|
|
|
-
|
|
|
+ var bladeLen = radius * 0.65;
|
|
|
+ var bladeW = radius * 0.18;
|
|
|
for (int i = 0; i < bladeCount; i++)
|
|
|
{
|
|
|
var angle = _rotationAngle + (360.0 / bladeCount) * i;
|
|
|
- var radians = angle * Math.PI / 180;
|
|
|
-
|
|
|
- var bladeX = centerX + Math.Cos(radians) * bladeLength * 0.5;
|
|
|
- var bladeY = centerY + Math.Sin(radians) * bladeLength * 0.5;
|
|
|
-
|
|
|
- // 缁樺埗鍙剁墖锛堝甫娓愬彉鏁堟灉锛
|
|
|
- var bladeBrush = new SolidColorBrush(IsRunning
|
|
|
- ? Color.FromArgb(200, statusBrush.Color.R, statusBrush.Color.G, statusBrush.Color.B)
|
|
|
- : Color.Parse("#546E7A"));
|
|
|
-
|
|
|
- var bladePath = new StreamGeometry();
|
|
|
- using (var ctx = bladePath.Open())
|
|
|
- {
|
|
|
- ctx.BeginFigure(new Point(bladeX - bladeWidth / 2, bladeY - bladeLength / 2), true);
|
|
|
- ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY - bladeLength / 2));
|
|
|
- ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY + bladeLength / 2));
|
|
|
- ctx.LineTo(new Point(bladeX - bladeWidth / 2, bladeY + bladeLength / 2));
|
|
|
- ctx.EndFigure(true);
|
|
|
- }
|
|
|
-
|
|
|
- // 鏃嬭浆鍙剁墖 - 浣跨敤鐭╅樀鍙樻崲
|
|
|
- var rotationRadians = angle * Math.PI / 180;
|
|
|
- var cos = Math.Cos(rotationRadians);
|
|
|
- var sin = Math.Sin(rotationRadians);
|
|
|
- var transform = new Matrix(cos, sin, -sin, cos, bladeX - bladeX * cos + bladeY * sin, bladeY - bladeX * sin - bladeY * cos);
|
|
|
+ var bx = cx + Math.Cos(angle * Math.PI / 180) * bladeLen * 0.5;
|
|
|
+ var by = cy + Math.Sin(angle * Math.PI / 180) * bladeLen * 0.5;
|
|
|
+ var bladeBrush = IsRunning ? new SolidColorBrush((statusBrush as SolidColorBrush)?.Color ?? Colors.Gray, 200) : ThemeHelper.TextDisabled();
|
|
|
+ var rad = angle * Math.PI / 180;
|
|
|
+ var cos = Math.Cos(rad); var sin = Math.Sin(rad);
|
|
|
+ var transform = new Matrix(cos, sin, -sin, cos, bx - bx * cos + by * sin, by - bx * sin - by * cos);
|
|
|
using (context.PushTransform(transform))
|
|
|
- {
|
|
|
- context.DrawGeometry(bladeBrush, null, bladePath);
|
|
|
- }
|
|
|
+ context.DrawRectangle(bladeBrush, null, new Rect(bx - bladeW / 2, by - bladeLen / 2, bladeW, bladeLen));
|
|
|
}
|
|
|
|
|
|
- // 缁樺埗涓績鍦嗭紙甯︽笎鍙橈級
|
|
|
- var centerRadius = radius * 0.25;
|
|
|
- var centerBrush = new SolidColorBrush(IsRunning ? statusBrush.Color : Color.Parse("#455A64"));
|
|
|
- context.DrawEllipse(centerBrush, null, new Rect(
|
|
|
- centerX - centerRadius,
|
|
|
- centerY - centerRadius,
|
|
|
- centerRadius * 2,
|
|
|
- centerRadius * 2));
|
|
|
-
|
|
|
- // 涓績楂樺厜
|
|
|
- var highlightBrush = new SolidColorBrush(Colors.White, 0.3);
|
|
|
- context.DrawEllipse(highlightBrush, null, new Rect(
|
|
|
- centerX - centerRadius * 0.5,
|
|
|
- centerY - centerRadius * 0.5,
|
|
|
- centerRadius,
|
|
|
- centerRadius));
|
|
|
+ // 涓績
|
|
|
+ var cr = radius * 0.25;
|
|
|
+ context.DrawEllipse(IsRunning ? statusColor : ThemeHelper.Border(), null, new Rect(cx - cr, cy - cr, cr * 2, cr * 2));
|
|
|
+ context.DrawEllipse(new SolidColorBrush(Colors.White, 0.3), null, new Rect(cx - cr * 0.5, cy - cr * 0.5, cr, cr));
|
|
|
|
|
|
- // 缁樺埗鐘舵佹寚绀虹伅
|
|
|
- var indicatorSize = 8;
|
|
|
- var indicatorX = bounds.Width - 20;
|
|
|
- var indicatorY = 10;
|
|
|
- var indicatorBrush = IsRunning
|
|
|
- ? new SolidColorBrush(Color.Parse("#4CAF50"))
|
|
|
- : new SolidColorBrush(Color.Parse("#78909C"));
|
|
|
+ // 鎸囩ず鐏
|
|
|
+ var indColor = IsRunning ? ThemeHelper.Success() : ThemeHelper.TextDisabled();
|
|
|
+ if (IsRunning) context.DrawEllipse(new SolidColorBrush((statusBrush as SolidColorBrush)?.Color ?? Colors.Gray, 0.3), null, new Rect(bounds.Width - 23, 7, 16, 16));
|
|
|
+ context.DrawEllipse(indColor, null, new Rect(bounds.Width - 20, 10, 10, 10));
|
|
|
|
|
|
- // 鎸囩ず鐏彂鍏
|
|
|
- if (IsRunning)
|
|
|
- {
|
|
|
- context.DrawEllipse(new SolidColorBrush(indicatorBrush.Color, 0.3), null,
|
|
|
- new Rect(indicatorX - 4, indicatorY - 4, 16, 16));
|
|
|
- }
|
|
|
-
|
|
|
- context.DrawEllipse(indicatorBrush, null,
|
|
|
- new Rect(indicatorX, indicatorY, indicatorSize, indicatorSize));
|
|
|
-
|
|
|
- // 缁樺埗鏂囧瓧鏍囩
|
|
|
+ // 鏂囧瓧
|
|
|
if (!string.IsNullOrEmpty(Text))
|
|
|
{
|
|
|
- var textBrush = new SolidColorBrush(Colors.White);
|
|
|
- var text = new FormattedText(Text, CultureInfo.CurrentCulture,
|
|
|
- FlowDirection.LeftToRight, typeface, 11, textBrush);
|
|
|
- var textPoint = new Point(
|
|
|
- centerX - text.Width / 2,
|
|
|
- bounds.Bottom - text.Height - 5);
|
|
|
- context.DrawText(text, textPoint);
|
|
|
+ var t = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 11, ThemeHelper.TextPrimary());
|
|
|
+ context.DrawText(t, new Point(cx - t.Width / 2, bounds.Bottom - t.Height - 5));
|
|
|
}
|
|
|
|
|
|
- // 缁樺埗棰戠巼鏄剧ず
|
|
|
+ // 棰戠巼
|
|
|
if (IsRunning)
|
|
|
{
|
|
|
- var freqStr = $"{Frequency:F0}Hz";
|
|
|
- var freqText = new FormattedText(freqStr, CultureInfo.CurrentCulture,
|
|
|
- FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 9,
|
|
|
- new SolidColorBrush(statusBrush.Color));
|
|
|
- context.DrawText(freqText, new Point(centerX - freqText.Width / 2, centerY + radius + 5));
|
|
|
+ var f = new FormattedText($"{Frequency:F0}Hz", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 9, statusColor);
|
|
|
+ context.DrawText(f, new Point(cx - f.Width / 2, cy + radius + 5));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- protected override Size MeasureOverride(Size availableSize)
|
|
|
- {
|
|
|
- return new Size(70, 80);
|
|
|
- }
|
|
|
+ protected override Size MeasureOverride(Size availableSize) => new Size(70, 80);
|
|
|
}
|