Initial commit: PulseDock System Monitor

This commit is contained in:
Developer
2026-07-23 12:37:00 +02:00
commit 2cfe8fb858
57 changed files with 3495 additions and 0 deletions
@@ -0,0 +1,100 @@
using System;
using System.Windows;
using System.Windows.Media;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color;
using Pen = System.Windows.Media.Pen;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace PulseDock.App.Controls
{
public class ProgressRingControl : FrameworkElement
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
nameof(Value),
typeof(double),
typeof(ProgressRingControl),
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(
nameof(StrokeThickness),
typeof(double),
typeof(ProgressRingControl),
new FrameworkPropertyMetadata(4.0, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty ProgressBrushProperty =
DependencyProperty.Register(
nameof(ProgressBrush),
typeof(Brush),
typeof(ProgressRingControl),
new FrameworkPropertyMetadata(Brushes.DarkViolet, FrameworkPropertyMetadataOptions.AffectsRender));
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public double StrokeThickness
{
get => (double)GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public Brush ProgressBrush
{
get => (Brush)GetValue(ProgressBrushProperty);
set => SetValue(ProgressBrushProperty, value);
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
double width = ActualWidth;
double height = ActualHeight;
if (width <= 0 || height <= 0) return;
double radius = (Math.Min(width, height) - StrokeThickness) / 2.0;
var center = new Point(width / 2.0, height / 2.0);
// Background circle
var bgPen = new Pen(new SolidColorBrush(Color.FromArgb(40, 255, 255, 255)), StrokeThickness);
bgPen.Freeze();
drawingContext.DrawEllipse(null, bgPen, center, radius, radius);
double pct = Math.Clamp(Value, 0.0, 100.0) / 100.0;
if (pct <= 0.001) return;
double angle = pct * 360.0;
if (angle >= 360.0) angle = 359.99; // Avoid full circle arc overlap issues
Point startPoint = new Point(center.X, center.Y - radius);
double radians = (angle - 90.0) * (Math.PI / 180.0);
Point endPoint = new Point(center.X + radius * Math.Cos(radians), center.Y + radius * Math.Sin(radians));
bool isLargeArc = angle > 180.0;
var geometry = new StreamGeometry();
using (var ctx = geometry.Open())
{
ctx.BeginFigure(startPoint, isFilled: false, isClosed: false);
ctx.ArcTo(endPoint, new Size(radius, radius), 0, isLargeArc, SweepDirection.Clockwise, isStroked: true, isSmoothJoin: true);
}
geometry.Freeze();
var fgPen = new Pen(ProgressBrush, StrokeThickness)
{
StartLineCap = PenLineCap.Round,
EndLineCap = PenLineCap.Round
};
fgPen.Freeze();
drawingContext.DrawGeometry(null, fgPen, geometry);
}
}
}
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Pen = System.Windows.Media.Pen;
using Point = System.Windows.Point;
namespace PulseDock.App.Controls
{
public class SparklineControl : FrameworkElement
{
public static readonly DependencyProperty ValuesProperty =
DependencyProperty.Register(
nameof(Values),
typeof(IEnumerable<float>),
typeof(SparklineControl),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty LineColorProperty =
DependencyProperty.Register(
nameof(LineColor),
typeof(Brush),
typeof(SparklineControl),
new FrameworkPropertyMetadata(Brushes.Cyan, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty LineThicknessProperty =
DependencyProperty.Register(
nameof(LineThickness),
typeof(double),
typeof(SparklineControl),
new FrameworkPropertyMetadata(1.5, FrameworkPropertyMetadataOptions.AffectsRender));
public IEnumerable<float>? Values
{
get => (IEnumerable<float>?)GetValue(ValuesProperty);
set => SetValue(ValuesProperty, value);
}
public Brush LineColor
{
get => (Brush)GetValue(LineColorProperty);
set => SetValue(LineColorProperty, value);
}
public double LineThickness
{
get => (double)GetValue(LineThicknessProperty);
set => SetValue(LineThicknessProperty, value);
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var values = Values?.ToArray();
if (values == null || values.Length < 2 || ActualWidth <= 0 || ActualHeight <= 0)
return;
double width = ActualWidth;
double height = ActualHeight;
float min = 0f;
float max = 100f; // Scale percentage or range dynamically
float actualMax = values.Max();
if (actualMax > 100f) max = actualMax;
var geometry = new StreamGeometry();
using (var ctx = geometry.Open())
{
double stepX = width / (values.Length - 1);
for (int i = 0; i < values.Length; i++)
{
double x = i * stepX;
float val = Math.Clamp(values[i], min, max);
double normY = (val - min) / (max - min);
double y = height - (normY * (height - 4)) - 2;
var point = new Point(x, y);
if (i == 0)
ctx.BeginFigure(point, isFilled: false, isClosed: false);
else
ctx.LineTo(point, isStroked: true, isSmoothJoin: true);
}
}
geometry.Freeze();
var pen = new Pen(LineColor, LineThickness);
pen.Freeze();
drawingContext.DrawGeometry(null, pen, geometry);
}
}
}