0

Visuals 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

enter image description here

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 and CompositionPath to create complex shapes? If it's not feasible, then
  • Is there any equivalent of CanvasPathGeometry for C++/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

Win2DRoundedRecangle

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.

Zoso
  • 3,273
  • 1
  • 16
  • 27
  • 1
    You create a `CompositionPath` from an object that implements both `IGeometrySource2D` and `IGeometrySource2DInterop`. `IGeometrySource2DInterop.GetGeometry` asks for a Direct2D geometry (`ID2D1Geometry`) that you can implement using "regular" C/C++. In most samples you'll find this is done using Win2D (which is reserved for UWP only which a stupid design decision). – Simon Mourier May 27 '21 at 08:57
  • As you mentioned, maybe you could do this via CanvasPathGeometry, you could draw such shape through combining those methods, for instance, AddSrc() and AddLine() methods. – dear_vv May 28 '21 at 08:47
  • 1
    We are consulting other engineers about your issue, there might be some delay. – dear_vv May 28 '21 at 08:48
  • @SimonMourier Could you please direct me to the references/documentation for `IGeometrySource2DInterop`? I couldn't find anything much apart from scant few issues mentioning that interface. – Zoso May 28 '21 at 16:37
  • 1
    This is the new Microsoft, all open source, but not all documented. The definition is in the Windows SDK here C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt\windows.graphics.interop.h and you'll find references in Win2D: https://github.com/microsoft/Win2D/blob/master/winrt/lib/geometry/CanvasGeometry.h – Simon Mourier May 28 '21 at 16:42
  • @AryaDing-MSFT Did you get a chance to seek any suggestions from MSFT engineers on this? I've updated the answer with my attempt at using `Win2D` but I'd still prefer not to have NuGet and stick to the SDK. Is the entire implementation of `Visual->Clip` using a `CompositionPath` not possible using just the SDK APIs? – Zoso Jun 01 '21 at 22:57

0 Answers0