using Avalonia; using Avalonia.Controls; using Avalonia.Media; using System.Globalization; namespace YZWater.Avalonia.Controls; public class StatusCard : Control { public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register(nameof(Title), "Device"); public static readonly StyledProperty StatusProperty = AvaloniaProperty.Register(nameof(Status), "RUNNING"); public static readonly StyledProperty IconProperty = AvaloniaProperty.Register(nameof(Icon), "P1"); public static readonly StyledProperty IsActiveProperty = AvaloniaProperty.Register(nameof(IsActive), false); public static readonly StyledProperty ActiveColorProperty = AvaloniaProperty.Register(nameof(ActiveColor)); public static readonly StyledProperty InactiveColorProperty = AvaloniaProperty.Register(nameof(InactiveColor)); public string Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); } public string Status { get => GetValue(StatusProperty); set => SetValue(StatusProperty, value); } public string Icon { get => GetValue(IconProperty); set => SetValue(IconProperty, value); } public bool IsActive { get => GetValue(IsActiveProperty); set => SetValue(IsActiveProperty, value); } public IBrush ActiveColor { get => GetValue(ActiveColorProperty); set => SetValue(ActiveColorProperty, value); } public IBrush InactiveColor { get => GetValue(InactiveColorProperty); set => SetValue(InactiveColorProperty, value); } static StatusCard() { AffectsRender(TitleProperty, StatusProperty, IconProperty, IsActiveProperty, ActiveColorProperty, InactiveColorProperty); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); ThemeHelper.ThemeChanged += OnThemeChanged; } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { ThemeHelper.ThemeChanged -= OnThemeChanged; base.OnDetachedFromVisualTree(e); } private void OnThemeChanged() => InvalidateVisual(); private static readonly Typeface s_monoTypeface = new("Consolas, monospace"); private static readonly Typeface s_labelTypeface = new("Microsoft YaHei"); public override void Render(DrawingContext context) { base.Render(context); var bounds = new Rect(Bounds.Size); var statusColor = IsActive ? (ActiveColor ?? ThemeHelper.Success) : (InactiveColor ?? ThemeHelper.TextDisabled); var statusBrush = statusColor as SolidColorBrush; var statusColorValue = statusBrush?.Color ?? Colors.Gray; context.DrawRectangle(ThemeHelper.PanelBg, null, bounds); context.DrawRectangle(statusColor, null, new Rect(0, 0, 3, bounds.Height)); var ledX = 12.0; var ledY = bounds.Height / 2 - 5; if (IsActive) context.DrawEllipse(new SolidColorBrush(statusColorValue, 0.3), null, new Rect(ledX - 3, ledY - 3, 16, 16)); context.DrawEllipse(statusColor, null, new Rect(ledX, ledY, 10, 10)); var iconText = new FormattedText(Icon, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_monoTypeface, 11, ThemeHelper.TextPrimary); context.DrawText(iconText, new Point(28, 6)); var titleText = new FormattedText(Title, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_labelTypeface, 10, ThemeHelper.TextSecondary); context.DrawText(titleText, new Point(28, 22)); var statusText = new FormattedText(Status, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_monoTypeface, 9, statusColor); context.DrawText(statusText, new Point(bounds.Width - statusText.Width - 10, bounds.Height / 2 - statusText.Height / 2)); } protected override Size MeasureOverride(Size availableSize) => new Size(230, 42); }