mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-24 10:12:35 +08:00
153 lines
5.1 KiB
C#
153 lines
5.1 KiB
C#
using AtomUI.Media;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Media;
|
|
using Avalonia.Utilities;
|
|
|
|
namespace AtomUI.Controls.Utils;
|
|
|
|
/// <summary>
|
|
/// Contains helper methods for rendering a <see cref="Border" />'s background and border to a given context.
|
|
/// </summary>
|
|
internal class BorderRenderHelper
|
|
{
|
|
private bool _useComplexRendering;
|
|
private Geometry? _backgroundGeometryCache;
|
|
private Geometry? _borderGeometryCache;
|
|
private Size _size;
|
|
private Thickness _borderThickness;
|
|
private CornerRadius _cornerRadius;
|
|
private BackgroundSizing _backgroundSizing;
|
|
private bool _initialized;
|
|
private IPen? _cachedPen;
|
|
|
|
private void Update(Size finalSize, Thickness borderThickness, CornerRadius cornerRadius,
|
|
BackgroundSizing backgroundSizing)
|
|
{
|
|
_size = finalSize;
|
|
_borderThickness = borderThickness;
|
|
_cornerRadius = cornerRadius;
|
|
_backgroundSizing = backgroundSizing;
|
|
_initialized = true;
|
|
|
|
if (borderThickness.IsUniform &&
|
|
cornerRadius.IsUniform &&
|
|
backgroundSizing == BackgroundSizing.CenterBorder)
|
|
{
|
|
_backgroundGeometryCache = null;
|
|
_borderGeometryCache = null;
|
|
_useComplexRendering = false;
|
|
}
|
|
else
|
|
{
|
|
_useComplexRendering = true;
|
|
|
|
var boundRect = new Rect(finalSize);
|
|
var innerRect = boundRect.Deflate(borderThickness);
|
|
|
|
if (innerRect.Width != 0 && innerRect.Height != 0)
|
|
{
|
|
var backgroundOuterKeypoints = RoundRectGeometryBuilder.CalculateRoundedCornersRectangleWinUI(
|
|
boundRect,
|
|
borderThickness,
|
|
cornerRadius,
|
|
backgroundSizing);
|
|
|
|
var backgroundGeometry = new StreamGeometry();
|
|
using (var ctx = backgroundGeometry.Open())
|
|
{
|
|
RoundRectGeometryBuilder.DrawRoundedCornersRectangle(ctx, ref backgroundOuterKeypoints);
|
|
}
|
|
|
|
_backgroundGeometryCache = backgroundGeometry;
|
|
}
|
|
else
|
|
{
|
|
_backgroundGeometryCache = null;
|
|
}
|
|
|
|
if (boundRect.Width != 0 && boundRect.Height != 0)
|
|
{
|
|
var borderInnerKeypoints = RoundRectGeometryBuilder.CalculateRoundedCornersRectangleWinUI(
|
|
boundRect,
|
|
borderThickness,
|
|
cornerRadius,
|
|
BackgroundSizing.InnerBorderEdge);
|
|
var borderOuterKeypoints = RoundRectGeometryBuilder.CalculateRoundedCornersRectangleWinUI(
|
|
boundRect,
|
|
borderThickness,
|
|
cornerRadius,
|
|
BackgroundSizing.OuterBorderEdge);
|
|
|
|
var borderInnerGeometry = new StreamGeometry();
|
|
using (var ctx = borderInnerGeometry.Open())
|
|
{
|
|
RoundRectGeometryBuilder.DrawRoundedCornersRectangle(ctx, ref borderInnerKeypoints);
|
|
}
|
|
|
|
var borderOuterGeometry = new StreamGeometry();
|
|
using (var ctx = borderOuterGeometry.Open())
|
|
{
|
|
RoundRectGeometryBuilder.DrawRoundedCornersRectangle(ctx, ref borderOuterKeypoints);
|
|
}
|
|
|
|
_borderGeometryCache =
|
|
new CombinedGeometry(GeometryCombineMode.Exclude, borderOuterGeometry, borderInnerGeometry);
|
|
}
|
|
else
|
|
{
|
|
_borderGeometryCache = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Render(
|
|
DrawingContext context,
|
|
Size finalSize,
|
|
Thickness borderThickness,
|
|
CornerRadius cornerRadius,
|
|
BackgroundSizing backgroundSizing,
|
|
IBrush? background,
|
|
IBrush? borderBrush,
|
|
BoxShadows boxShadows)
|
|
{
|
|
if (_size != finalSize
|
|
|| _borderThickness != borderThickness
|
|
|| _cornerRadius != cornerRadius
|
|
|| _backgroundSizing != backgroundSizing
|
|
|| !_initialized)
|
|
{
|
|
Update(finalSize, borderThickness, cornerRadius, backgroundSizing);
|
|
}
|
|
|
|
if (_useComplexRendering)
|
|
{
|
|
if (_backgroundGeometryCache != null)
|
|
{
|
|
context.DrawGeometry(background, null, _backgroundGeometryCache);
|
|
}
|
|
|
|
if (_borderGeometryCache != null)
|
|
{
|
|
context.DrawGeometry(borderBrush, null, _borderGeometryCache);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var thickness = _borderThickness.Top;
|
|
|
|
PenUtils.TryModifyOrCreate(ref _cachedPen, borderBrush, thickness);
|
|
|
|
var rect = new Rect(_size);
|
|
if (!MathUtilities.IsZero(thickness))
|
|
{
|
|
rect = rect.Deflate(thickness * 0.5);
|
|
}
|
|
|
|
var rrect = new RoundedRect(rect, _cornerRadius.TopLeft, _cornerRadius.TopRight,
|
|
_cornerRadius.BottomRight, _cornerRadius.BottomLeft);
|
|
|
|
context.DrawRectangle(background, _cachedPen, rrect, boxShadows);
|
|
}
|
|
}
|
|
} |