Skip to content

Commit f5c875b

Browse files
authored
Merge pull request #17 from iniceice88/feat/mac_mouse_support
Implement basic mouse support for macOS
2 parents dd74210 + f715f3e commit f5c875b

File tree

3 files changed

+135
-3
lines changed

3 files changed

+135
-3
lines changed

Source/OxyPlot.Maui.Skia/AppHostBuilderExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public static MauiAppBuilder UseOxyPlotSkia(this MauiAppBuilder builder)
1414
#elif WINDOWS
1515
effects.Add<MyTouchEffect, Windows.Effects.PlatformTouchEffect>();
1616
#elif MACCATALYST
17-
// not implemented
17+
effects.Add<MyTouchEffect, macOS.Effects.PlatformTouchEffect>();
1818
#elif __IOS__
1919
effects.Add<MyTouchEffect, ios.Effects.PlatformTouchEffect>();
2020
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using CoreGraphics;
2+
using Foundation;
3+
using Microsoft.Maui.Controls.Platform;
4+
using OxyPlot.Maui.Skia.Effects;
5+
using UIKit;
6+
7+
namespace OxyPlot.Maui.Skia.macOS.Effects;
8+
9+
public class PlatformTouchEffect : PlatformEffect
10+
{
11+
private UIView _view;
12+
private TouchRecognizer _touchRecognizer;
13+
private MyTouchEffect _touchEffect;
14+
protected override void OnAttached()
15+
{
16+
_view = Control ?? Container;
17+
_touchEffect = Element.Effects.OfType<MyTouchEffect>().FirstOrDefault();
18+
19+
if (_touchEffect == null || _view == null) return;
20+
21+
_touchRecognizer = new TouchRecognizer(Element, _touchEffect);
22+
_view.AddGestureRecognizer(_touchRecognizer);
23+
_view.AddGestureRecognizer(GetMouseWheelRecognizer(_view));
24+
}
25+
26+
protected override void OnDetached()
27+
{
28+
if (_touchRecognizer != null)
29+
{
30+
_touchRecognizer.Detach();
31+
_view.RemoveGestureRecognizer(_touchRecognizer);
32+
}
33+
}
34+
35+
// https://github.com/dotnet/maui/issues/16130
36+
private UIPanGestureRecognizer GetMouseWheelRecognizer(UIView v)
37+
{
38+
return new UIPanGestureRecognizer((e) =>
39+
{
40+
if (e.State == UIGestureRecognizerState.Ended)
41+
return;
42+
43+
var isZoom = e.NumberOfTouches == 0;
44+
if (!isZoom) return;
45+
46+
var l = e.LocationInView(v);
47+
var t = e.TranslationInView(v);
48+
var deltaX = t.X / 2;
49+
var deltaY = t.Y / 2;
50+
var delta = deltaY != 0 ? deltaY : deltaX;
51+
52+
var tolerance = 5;
53+
if (Math.Abs(delta) < tolerance) return;
54+
55+
var pointerX = l.X - t.X;
56+
var pointerY = l.Y - t.Y;
57+
var locations = new[] { new Point(pointerX, pointerY) };
58+
59+
var eventArgs = new TouchActionEventArgs(0, TouchActionType.MouseWheel, locations, false)
60+
{
61+
MouseWheelDelta = (int)delta
62+
};
63+
64+
_touchEffect.OnTouchAction(Element, eventArgs);
65+
})
66+
{
67+
AllowedScrollTypesMask = UIScrollTypeMask.Discrete | UIScrollTypeMask.Continuous,
68+
MinimumNumberOfTouches = 0,
69+
ShouldRecognizeSimultaneously = (_, _) => true
70+
};
71+
}
72+
}
73+
74+
internal class TouchRecognizer : UIGestureRecognizer
75+
{
76+
private readonly Microsoft.Maui.Controls.Element _element;
77+
private readonly MyTouchEffect _touchEffect;
78+
private uint _activeTouchesCount = 0;
79+
80+
public TouchRecognizer(Microsoft.Maui.Controls.Element element, MyTouchEffect touchEffect)
81+
{
82+
this._element = element;
83+
this._touchEffect = touchEffect;
84+
ShouldRecognizeSimultaneously = (_, _) => true;
85+
}
86+
87+
public void Detach()
88+
{
89+
ShouldRecognizeSimultaneously = null;
90+
}
91+
92+
public override void TouchesBegan(NSSet touches, UIEvent evt)
93+
{
94+
base.TouchesBegan(touches, evt);
95+
_activeTouchesCount += touches.Count.ToUInt32();
96+
FireEvent(touches, TouchActionType.Pressed, true);
97+
}
98+
99+
public override void TouchesMoved(NSSet touches, UIEvent evt)
100+
{
101+
base.TouchesMoved(touches, evt);
102+
103+
if (_activeTouchesCount == touches.Count.ToUInt32())
104+
{
105+
FireEvent(touches, TouchActionType.Moved, true);
106+
}
107+
}
108+
109+
public override void TouchesEnded(NSSet touches, UIEvent evt)
110+
{
111+
base.TouchesEnded(touches, evt);
112+
_activeTouchesCount -= touches.Count.ToUInt32();
113+
FireEvent(touches, TouchActionType.Released, false);
114+
}
115+
116+
private void FireEvent(NSSet touches, TouchActionType actionType, bool isInContact)
117+
{
118+
UITouch[] uiTouches = touches.Cast<UITouch>().ToArray();
119+
long id = ((IntPtr)uiTouches.First().Handle).ToInt64();
120+
Point[] points = new Point[uiTouches.Length];
121+
122+
for (int i = 0; i < uiTouches.Length; i++)
123+
{
124+
CGPoint cgPoint = uiTouches[i].LocationInView(View);
125+
points[i] = new(cgPoint.X, cgPoint.Y);
126+
}
127+
_touchEffect.OnTouchAction(_element, new(id, actionType, points, isInContact));
128+
}
129+
}

Source/OxyPlot.Maui.Skia/PlotController.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ public PlotController()
1717
this.BindTouchDown(cmd);
1818

1919
#if WINDOWS
20-
this.BindMouseWheel(OxyPlot.PlotCommands.ZoomWheel);
21-
this.BindMouseWheel(OxyModifierKeys.Control, OxyPlot.PlotCommands.ZoomWheelFine);
20+
this.BindMouseWheel(OxyPlot.PlotCommands.ZoomWheel);
21+
this.BindMouseWheel(OxyModifierKeys.Control, OxyPlot.PlotCommands.ZoomWheelFine);
22+
#endif
23+
#if MACCATALYST
24+
this.BindMouseWheel(OxyPlot.PlotCommands.ZoomWheel);
2225
#endif
2326
}
2427
}

0 commit comments

Comments
 (0)