Open arcadiogarcia opened 3 years ago
Hi @arcadiogarcia, good question. This type depends on Windows.UI.Input.Inking and there is no corresponding WinUI 3 type yet. We should update our docs to reflect this, so I've opened an internal work item for us to do so. In the meantime, I'd recommend checking the WinUI 3 docs and WinUI repo for the latest updates on inking support in WinUI 3.
Hi @duncanmacmichael it seems that InkStroke is now part of WinUI3. Any update to Win2D to support DrawInk?
You can achieve a similar effect through offscreen rendering. Below is a similar example. I think it should be easy to customize the pen stroke style.
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="FluentPdf.Views.D2DCanvas"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"
xmlns:converters="using:FluentPdf.Converters"
mc:Ignorable="d">
<UserControl.Resources>
<converters:IsDrawingConverter x:Key="IsDrawingConverter" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind ViewModel.IsDrawing,Mode=OneWay,Converter={StaticResource IsDrawingConverter}}" ></TextBlock>
</StackPanel>
</Grid>
<xaml:CanvasControl Grid.Row="1" x:Name="DCanvas" CreateResources="DCreateResources" Draw="DDraw"
ClearColor="CornFlowerBlue" />
</Grid>
</UserControl>
using System;
using System.Collections.ObjectModel;
using Microsoft.Graphics.Canvas.UI;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using System.Threading.Tasks;
using Microsoft.Graphics.Canvas;
using Microsoft.UI;
using System.ComponentModel;
using System.Runtime.CompilerServices;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace FluentPdf.Views
{
public class DCanvasPoint(float x, float y, float pressure)
{
public float X { get; set; } = x;
public float Y { get; set; } = y;
public float Pressure = pressure;
}
public class DCanvasLine
{
public ObservableCollection<DCanvasPoint> LinePoints = new();
public DCanvasPoint StartPoint { get; set; }
public DCanvasPoint EndPoint { get; set; }
public int PointsCount => LinePoints.Count;
public void AddPoint(DCanvasPoint point)
{
if (PointsCount == 0)
{
StartPoint = point;
}
LinePoints.Add(point);
EndPoint = point;
}
}
public class D2DCanvasViewModel : INotifyPropertyChanged
{
private bool _isDrawing;
private bool _isDrawingReady = false;
// public CanvasBitmap DBitmap;
public CanvasRenderTarget InkPresenter;
public void D2DCanvasViewModelInit(int width, int height)
{
InkPresenter = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), width, height, 144);
}
public ObservableCollection<DCanvasLine> DLines { get; set; } = new();
public DCanvasLine CurrentDLine;
public void AddToLines()
{
DLines.Add(CurrentDLine);
CurrentDLine = null;
}
public void AddPointToCurrentDLine(DCanvasPoint point)
{
CurrentDLine ??= new DCanvasLine();
CurrentDLine.AddPoint(point);
}
public bool IsDrawingReady
{
get => _isDrawingReady;
set
{
if (_isDrawingReady == value) return;
_isDrawingReady = value;
OnPropertyChanged();
}
}
public bool IsDrawing
{
get => _isDrawing;
set
{
if (_isDrawing == value) return;
_isDrawing = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public sealed partial class D2DCanvas
{
// private CanvasSolidColorBrush _redBrush;
public D2DCanvasViewModel ViewModel;
public D2DCanvas()
{
this.InitializeComponent();
ViewModel = new D2DCanvasViewModel();
Loaded += D2DCanvas_Loaded;
Unloaded += D2DCanvas_Unloaded;
SizeChanged += D2DCanvas_SizeChanged;
// DCanvas.FocusEngaged += DCanvas_FocusEngaged;
// DCanvas.FocusDisengaged += DCanvas_FocusDisengaged;
DCanvas.PointerPressed += DCanvas_PointerPressed;
DCanvas.PointerMoved += DCanvas_PointerMoved;
DCanvas.PointerReleased += DCanvas_PointerReleased;
DCanvas.PointerExited += DCanvas_PointerExited;
}
private void DCanvas_PointerExited(object sender, PointerRoutedEventArgs e)
{
ViewModel.IsDrawing = false;
}
private void DCanvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (ViewModel.IsDrawing)
{
ViewModel.AddToLines();
}
ViewModel.IsDrawing = false;
}
private void DCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (!ViewModel.IsDrawing) return;
var point = e.GetCurrentPoint(DCanvas);
var pressure = point.Properties.Pressure;
if (!(pressure > 0)) return;
// ViewModel.Points.Add(new CanvasPoint(point.Position._x, point.Position._y, pressure));
var previousPoint = ViewModel.CurrentDLine?.EndPoint;
ViewModel.AddPointToCurrentDLine(new DCanvasPoint(point.Position._x, point.Position._y, pressure));
DCanvas.Invalidate();
using var ds = ViewModel.InkPresenter.CreateDrawingSession();
if (previousPoint != null)
ds.DrawLine(previousPoint.X, previousPoint.Y, point.Position._x, point.Position._y, Colors.Black,
pressure);
// DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, DCanvas.Invalidate);
// Draw something
}
private void DCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
ViewModel.IsDrawing = true;
}
private void D2DCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
DCanvas.Invalidate();
}
private void D2DCanvas_Loaded(object sender, RoutedEventArgs e)
{
ViewModel.D2DCanvasViewModelInit((int)DCanvas.ActualWidth, (int)DCanvas.ActualHeight);
}
private void D2DCanvas_Unloaded(object sender, RoutedEventArgs e)
{
DCanvas.RemoveFromVisualTree();
DCanvas = null;
}
private void DCreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
args.TrackAsyncAction(DCreateResourcesAsync(sender).AsAsyncAction());
}
Task DCreateResourcesAsync(CanvasControl sender)
{
return Task.CompletedTask;
// Load bitmaps, create brushes, etc.
// ViewModel.DBitmap = await CanvasBitmap.LoadAsync(sender, "Assets/sample.png");
}
private void DDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
using var ds = args.DrawingSession;
// Draw something
// ds.DrawImage(ViewModel.DBitmap);
ds.DrawImage(ViewModel.InkPresenter);
}
}
}
Also hitting this issue. Would be great to see support for Ink now that it's supported in WinUI3.
The DrawInk methods seem gated by an ifdef for WINUI3_SUPPORTS_INKING.
I can see there's a flag to set FunctionLevelLWINUI3_SUPPORTS_INKING
to true in the release profile Win2d.cpp.props..
What else do we need to do to get this enabled @duncanmacmichael?
The DrawInk method shows up in the WinUI3 docs (https://microsoft.github.io/Win2D/WinUI3/html/Overload_Microsoft_Graphics_Canvas_CanvasDrawingSession_DrawInk.htm) but it is missing in the actual package.
Is this an error in the docs or is this a work in progress? Is there a rough timeline for when this functionality will show up?