Visual
s in UWP/WinUI can have a Clip
applied to them which is an instance of a CompositionClip
. One of the types of CompositionClip
is a GeometricClip
which can have a Geometry
of various types derived from the CompositionGeometry
class. I'm seeking to have a clip that has the shape of a rounded rectangle but with different elliptical corner radii as follows
This would ideally be suited for the CompositionRoundedRectangleGeometry
but that class has a limitation that it supports having the same elliptical radius on all four corners, not allowing for different radii. So that leaves CompositionPathGeometry
whose Path
is defined by a CompositionPath
instance. This is where I've reached a dead end.
This CompositionPath
implements the IGeometrySource2D
interface. I couldn't figure out how to use this IGeometrySource2D
interface to construct a complex path with lines and curves. Searching online led to this article which too skirts using that interface and instead uses the classes built around CanvasPathGeometry
which is from the Windows Community Toolkit
and, if I understand correctly, only meant for C#
projects as per this GitHub page and won't work for me since I need something in C++.
So the questions are:
- How do we use
IGeometrySource2D
andCompositionPath
to create complex shapes? If it's not feasible, then - Is there any equivalent of
CanvasPathGeometry
forC++/WinRT
language projection?
P.S. I'm aware that WinUI 3 offers RectangleClip
(as per this answer) that would work for my case but that isn't available in UWP, so that's not a feasible solution for me.
EDIT:
Here's an attempt using Win2D.UWP
NuGet package, based on the suggestions/pointers shared in the comments.
auto visual = _compositor->CreateSpriteVisual();
visual->Size = float2(500.0f);
visual->Offset = float3(50, 50, 0);
visual->Brush = _compositor->CreateColorBrush(Colors::Red);
auto canvasPathBuilder = ref new CanvasPathBuilder(ref new CanvasDevice());
canvasPathBuilder->BeginFigure(radius.topLeft.x, 0);
canvasPathBuilder->AddLine(visual->Size.x - radius.topRight.x, 0);
canvasPathBuilder->AddArc(float2(visual->Size.x , radius.topRight.y ), radius.topRight.x, radius.topRight.y,
0, CanvasSweepDirection::Clockwise, CanvasArcSize::Small);
canvasPathBuilder->AddLine(visual->Size.x, visual->Size.y - radius.bottomRight.y);
canvasPathBuilder->AddArc(float2(visual->Size.x - radius.bottomRight.x, visual->Size.y), radius.bottomRight.x, radius.bottomRight.y,
0, CanvasSweepDirection::Clockwise, CanvasArcSize::Small);
canvasPathBuilder->AddLine(radius.bottomLeft.x, visual->Size.y);
canvasPathBuilder->AddArc(float2(0, visual->Size.y - radius.bottomLeft.y), radius.bottomLeft.x, radius.bottomLeft.y,
0, CanvasSweepDirection::Clockwise, CanvasArcSize::Small);
canvasPathBuilder->AddLine(0, radius.topLeft.y);
canvasPathBuilder->AddArc(float2(radius.topLeft.x, 0), radius.topLeft.x, radius.topLeft.y,
0, CanvasSweepDirection::Clockwise, CanvasArcSize::Small);
canvasPathBuilder->EndFigure(CanvasFigureLoop::Closed);
auto canvasGeometry = CanvasGeometry::CreatePath(canvasPathBuilder);
auto compositionPath = ref new CompositionPath(canvasGeometry);
auto pathGeometry = _compositor->CreatePathGeometry();
pathGeometry->Path = compositionPath;
visual->Clip = _compositor->CreateGeometricClip(pathGeometry);
This appears to work
Now, the next step would be to work to remove the Win2D
dependency for CanvasPath
et al and to use ID2D1Geometry
and other interfaces to supply the IGeomterySource2D
since I would prefer not having NuGet packages as a project dependency.