Repository: beeware/toga

Issue:
Canvas is failing when parameters are of type `np.float64`
**Describe the bug**

After the new changes in version 3.0 of Pythonnet, there is not longer an implicit conversion between `np.float64` to `float`.
This causes crashes when trying to use `Canvas` such as in issue beeware/toga-chart#16.

While some of the problem was fixes in #1558, some of the errors are still occurring. Here is an example I encountered in [Eddington-GUI](https://github.com/EddLabs/eddington-gui):

```
Traceback (most recent call last):
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga_winforms\widgets\canvas.py", line 172, in bezier_curve_to
    PointF(*draw_context.last_point),
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga\widgets\canvas.py", line 876, in _draw
    impl.bezier_curve_to(
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga\widgets\canvas.py", line 43, in _draw
    obj._draw(impl, *args, **kwargs)
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga\widgets\canvas.py", line 407, in _draw
    obj._draw(impl, *args, **kwargs)
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga\widgets\canvas.py", line 43, in _draw
    obj._draw(impl, *args, **kwargs)
  File "C:\Users\sagi\PycharmProjects\eddington-gui\venv\lib\site-packages\toga_winforms\widgets\canvas.py", line 93, in winforms_paint
    self.interface._draw(self, draw_context=context)
   at Python.Runtime.PythonException.ThrowLastAsClrException()
   at Python.Runtime.Dispatcher.TrueDispatch(Object[] args)
   at Python.Runtime.Dispatcher.Dispatch(Object[] args)
   at __System_Windows_Forms_PaintEventHandlerDispatcher.Invoke(Object , PaintEventArgs )
   at System.Windows.Forms.Control.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
No method matches given arguments for PointF..ctor: (<class 'numpy.float64'>, <class 'numpy.float64'>)
```

**To Reproduce**
Steps to reproduce the behavior:
1. Go to the `Canvas` example in a Windows computer
2. Try to use `np.float64` instead of `float`
3. Run and see it crash

**Expected behavior**
It should not crash.

**Environment:**
 - Operating System: Windows
 - Python version: 3.10
 - Software versions:
   - Briefcase: Latest
   - Toga: Latest
   - ...

**Additional context**
Add any other context about the problem here.



Discussion:
As before, at seems like a quick fix. Just adding more conversions in the Winforms implementation to `float`.
@freakboy3742 , I just need you OK that I can make that change.
@saroad2 +1 - I fixed the casts that were obvious in #1558, but if you're seeing additional ones, then go ahead and cast as required.

Resolving patch:
diff --git a/src/winforms/toga_winforms/widgets/canvas.py b/src/winforms/toga_winforms/widgets/canvas.py
--- a/src/winforms/toga_winforms/widgets/canvas.py
+++ b/src/winforms/toga_winforms/widgets/canvas.py
@@ -160,26 +160,31 @@ def move_to(self, x, y, draw_context, *args, **kwargs):
         draw_context.last_point = (x, y)
 
     def line_to(self, x, y, draw_context, *args, **kwargs):
-        ox, oy = int(draw_context.last_point[0]), int(draw_context.last_point[1])
-        x, y = int(x), int(y)
-        draw_context.current_path.AddLine(ox, oy, x, y)
+        draw_context.current_path.AddLine(
+            float(draw_context.last_point[0]), float(draw_context.last_point[1]),
+            float(x), float(y)
+        )
         draw_context.last_point = (x, y)
 
     # Basic shapes
 
     def bezier_curve_to(self, cp1x, cp1y, cp2x, cp2y, x, y, draw_context, *args, **kwargs):
-        point1, point2, point3, point4 = (
-            PointF(*draw_context.last_point),
-            PointF(cp1x, cp1y),
-            PointF(cp2x, cp2y),
-            PointF(x, y)
+        # Workaround for Pythonnet#1833 requires an explicit cast to float
+        draw_context.current_path.AddBezier(
+            PointF(float(draw_context.last_point[0]), float(draw_context.last_point[1])),
+            PointF(float(cp1x), float(cp1y)),
+            PointF(float(cp2x), float(cp2y)),
+            PointF(float(x), float(y)),
         )
-        draw_context.current_path.AddBezier(point1, point2, point3, point4)
         draw_context.last_point = (x, y)
 
     def quadratic_curve_to(self, cpx, cpy, x, y, draw_context, *args, **kwargs):
-        point1, point2, point3 = PointF(*draw_context.last_point), PointF(cpx, cpy), PointF(x, y)
-        draw_context.current_path.AddCurve([point1, point2, point3])
+        # Workaround for Pythonnet#1833 requires an explicit cast to float
+        draw_context.current_path.AddCurve([
+            PointF(float(draw_context.last_point[0]), float(draw_context.last_point[1])),
+            PointF(float(cpx), float(cpy)),
+            PointF(float(x), float(y)),
+        ])
         draw_context.last_point = (x, y)
 
     def arc(
@@ -221,7 +226,10 @@ def ellipse(
             draw_context,
             *args,
             **kwargs):
-        rect = RectangleF(float(x - radiusx), float(y - radiusy), float(2 * radiusx), float(2 * radiusy))
+        rect = RectangleF(
+            float(x - radiusx), float(y - radiusy),
+            float(2 * radiusx), float(2 * radiusy)
+        )
         draw_context.current_path.AddArc(
             rect,
             math.degrees(startangle),


Test patch: