118 lines
3.9 KiB
C#
118 lines
3.9 KiB
C#
|
|
using System;
|
|||
|
|
using System.Runtime.CompilerServices;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Media;
|
|||
|
|
using WPFDark.Internals;
|
|||
|
|
|
|||
|
|
|
|||
|
|
namespace WPFDark
|
|||
|
|
{
|
|||
|
|
public readonly ref struct LayoutRounder
|
|||
|
|
{
|
|||
|
|
public readonly double DpiScale;
|
|||
|
|
|
|||
|
|
private readonly FrameworkElement element;
|
|||
|
|
private readonly double inverseDpiScale;
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public LayoutRounder(FrameworkElement element)
|
|||
|
|
{
|
|||
|
|
this.element = element;
|
|||
|
|
DpiScale = element.PixelsPerDip();
|
|||
|
|
inverseDpiScale = 1d / DpiScale;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public Pen GetBorderPen(ByteColor color)
|
|||
|
|
=> Caches.GetPen(color, RoundLayoutValue(FrameworkElementExtensions.BorderWidth));
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public double RoundRenderWidth(bool isWithBorder)
|
|||
|
|
{
|
|||
|
|
return isWithBorder
|
|||
|
|
? RoundLayoutValue(element.RenderSize.Width - FrameworkElementExtensions.BorderWidth)
|
|||
|
|
: RoundLayoutValue(element.RenderSize.Width);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public double RoundRenderHeight(bool isWithBorder)
|
|||
|
|
{
|
|||
|
|
return isWithBorder
|
|||
|
|
? RoundLayoutValue(element.RenderSize.Height - FrameworkElementExtensions.BorderWidth)
|
|||
|
|
: RoundLayoutValue(element.RenderSize.Height);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public Rect RoundRenderRectangle(bool isWithBorder)
|
|||
|
|
{
|
|||
|
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
|||
|
|
if (isWithBorder)
|
|||
|
|
{
|
|||
|
|
return new Rect(
|
|||
|
|
RoundLayoutValue(FrameworkElementExtensions.BorderHalfWidth),
|
|||
|
|
RoundLayoutValue(FrameworkElementExtensions.BorderHalfWidth),
|
|||
|
|
RoundRenderWidth(isWithBorder),
|
|||
|
|
RoundRenderHeight(isWithBorder));
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return new Rect(0, 0, RoundRenderWidth(isWithBorder),
|
|||
|
|
RoundRenderHeight(isWithBorder));
|
|||
|
|
}
|
|||
|
|
// ReSharper restore ConditionIsAlwaysTrueOrFalse
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public ImmutableRect_double RoundLayoutRect(in ImmutableRect_double rect)
|
|||
|
|
{
|
|||
|
|
return new ImmutableRect_double(
|
|||
|
|
RoundLayoutValue(rect.X),
|
|||
|
|
RoundLayoutValue(rect.Y),
|
|||
|
|
RoundLayoutValue(rect.Width),
|
|||
|
|
RoundLayoutValue(rect.Height));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public Rect RoundLayoutRect(double x, double y, double w, double h)
|
|||
|
|
{
|
|||
|
|
return new Rect(
|
|||
|
|
RoundLayoutValue(x),
|
|||
|
|
RoundLayoutValue(y),
|
|||
|
|
RoundLayoutValue(w),
|
|||
|
|
RoundLayoutValue(h));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
|
public Rect RoundLayoutRect(Rect rect)
|
|||
|
|
{
|
|||
|
|
return new Rect(
|
|||
|
|
RoundLayoutValue(rect.X),
|
|||
|
|
RoundLayoutValue(rect.Y),
|
|||
|
|
RoundLayoutValue(rect.Width),
|
|||
|
|
RoundLayoutValue(rect.Height));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public double RoundLayoutValue(double value)
|
|||
|
|
{
|
|||
|
|
double newValue;
|
|||
|
|
|
|||
|
|
if (NumberHelper.AreClose(DpiScale, 1d) == false)
|
|||
|
|
{
|
|||
|
|
newValue = Math.Round(value * DpiScale) * inverseDpiScale;
|
|||
|
|
|
|||
|
|
if (double.IsNaN(newValue) ||
|
|||
|
|
double.IsInfinity(newValue) ||
|
|||
|
|
NumberHelper.AreClose(newValue, double.MaxValue))
|
|||
|
|
{
|
|||
|
|
newValue = value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
newValue = value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return newValue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|