Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions source/Generic/SplashScreen/Helpers/SpinnerGeometryBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Windows;
using System.Windows.Media;

namespace SplashScreen.Helpers
{
internal static class SpinnerGeometryBuilder
{
internal static Geometry BuildDashGeometry(double spinnerSize, double thickness, double dashLengthPercent, int dashCount, bool roundedDashes)
{
var clampedDashCount = Math.Max(1, Math.Min(360, dashCount));
var innerSize = Math.Max(2.0, spinnerSize - thickness);
var radius = innerSize / 2.0;
var slotAngle = (2.0 * Math.PI) / clampedDashCount;
var clampedDashLengthPercent = Math.Max(1.0, Math.Min(100.0, dashLengthPercent));
var dashAngle = slotAngle * (clampedDashLengthPercent / 100.0);

var center = spinnerSize / 2.0;
var geometry = new PathGeometry();

for (var i = 0; i < clampedDashCount; i++)
{
var centerAngle = (-Math.PI / 2.0) + (i * slotAngle);
var startAngle = centerAngle - (dashAngle / 2.0);
var endAngle = centerAngle + (dashAngle / 2.0);
AddDashFigure(geometry, center, radius, startAngle, endAngle, dashAngle);
}

return geometry;
}

private static void AddDashFigure(PathGeometry geometry, double center, double radius, double startAngle, double endAngle, double dashAngle)
{
var normalizedDashAngle = Math.Max(0.0, dashAngle);
var fullCircleThreshold = (2.0 * Math.PI) - 0.0001;
var startPoint = PointOnCircle(center, radius, startAngle);

var figure = new PathFigure
{
StartPoint = startPoint,
IsClosed = false,
IsFilled = false
};

if (normalizedDashAngle >= fullCircleThreshold)
{
var middlePoint = PointOnCircle(center, radius, startAngle + Math.PI);

figure.Segments.Add(new ArcSegment
{
Point = middlePoint,
Size = new Size(radius, radius),
IsLargeArc = false,
SweepDirection = SweepDirection.Clockwise
});

figure.Segments.Add(new ArcSegment
{
Point = startPoint,
Size = new Size(radius, radius),
IsLargeArc = false,
SweepDirection = SweepDirection.Clockwise
});
}
else
{
var endPoint = PointOnCircle(center, radius, endAngle);
figure.Segments.Add(new ArcSegment
{
Point = endPoint,
Size = new Size(radius, radius),
IsLargeArc = normalizedDashAngle > Math.PI,
SweepDirection = SweepDirection.Clockwise
});
}

geometry.Figures.Add(figure);
}

private static Point PointOnCircle(double center, double radius, double angle)
{
return new Point(
center + (radius * Math.Cos(angle)),
center + (radius * Math.Sin(angle))
);
}
}
}
83 changes: 83 additions & 0 deletions source/Generic/SplashScreen/Helpers/SpinnerRenderHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SplashScreen.Helpers
{
internal static class SpinnerRenderHelper
{
internal static double ClampThickness(double thickness)
{
return Math.Max(0.5, thickness);
}

internal static double ClampDashLengthPercent(double dashLengthPercent)
{
return Math.Max(1.0, Math.Min(100.0, dashLengthPercent));
}

internal static int ClampDashCount(int dashCount)
{
return Math.Max(1, Math.Min(360, dashCount));
}

internal static double ClampSpinnerSize(double spinnerSize)
{
return Math.Max(4.0, spinnerSize);
}

internal static double CalculateRotationDurationSeconds(double baseSeconds, bool autoSpeed, double spinnerSize)
{
var normalizedBaseSeconds = baseSeconds;
if (normalizedBaseSeconds <= 0)
{
normalizedBaseSeconds = 3.0;
}

var durationSeconds = normalizedBaseSeconds;
if (autoSpeed)
{
var normalizedSize = spinnerSize / 50.0;
if (normalizedSize < 0.4)
{
normalizedSize = 0.4;
}

durationSeconds = normalizedBaseSeconds * normalizedSize;
}

if (durationSeconds < 0.25)
{
durationSeconds = 0.25;
}

if (durationSeconds > 20.0)
{
durationSeconds = 20.0;
}

return durationSeconds;
}

internal static void ApplySpinnerAppearance(Path spinnerPath, double spinnerSize, double thickness, double dashLengthPercent, int dashCount, bool roundedDashes)
{
if (spinnerPath == null)
{
return;
}

var normalizedThickness = ClampThickness(thickness);
var normalizedDashLengthPercent = ClampDashLengthPercent(dashLengthPercent);
var normalizedDashCount = ClampDashCount(dashCount);
var normalizedSpinnerSize = ClampSpinnerSize(spinnerSize);

spinnerPath.StrokeThickness = normalizedThickness;
spinnerPath.StrokeDashArray = null;
spinnerPath.StrokeDashOffset = 0;
spinnerPath.StrokeDashCap = PenLineCap.Flat;
spinnerPath.StrokeStartLineCap = roundedDashes ? PenLineCap.Round : PenLineCap.Flat;
spinnerPath.StrokeEndLineCap = roundedDashes ? PenLineCap.Round : PenLineCap.Flat;
spinnerPath.Data = SpinnerGeometryBuilder.BuildDashGeometry(normalizedSpinnerSize, normalizedThickness, normalizedDashLengthPercent, normalizedDashCount, roundedDashes);
}
}
}
25 changes: 25 additions & 0 deletions source/Generic/SplashScreen/Helpers/SplashSettingsSyncHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using SplashScreen.Models;

namespace SplashScreen.Helpers
{
internal static class SplashSettingsSyncHelper
{
internal static void ApplyGlobalIndicatorSettings(GeneralSplashSettings target, GeneralSplashSettings global)
{
if (target == null || global == null)
{
return;
}

target.EnableLoadingSpinner = global.EnableLoadingSpinner;
target.LoadingSpinnerSize = global.LoadingSpinnerSize;
target.LoadingSpinnerOpacity = global.LoadingSpinnerOpacity;
target.LoadingSpinnerThickness = global.LoadingSpinnerThickness;
target.LoadingSpinnerDashLength = global.LoadingSpinnerDashLength;
target.LoadingSpinnerDashCount = global.LoadingSpinnerDashCount;
target.LoadingSpinnerRoundedDashes = global.LoadingSpinnerRoundedDashes;
target.LoadingSpinnerRotationSeconds = global.LoadingSpinnerRotationSeconds;
target.EnableLoadingSpinnerAutoSpeed = global.EnableLoadingSpinnerAutoSpeed;
}
}
}
Loading