Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 3a59f02

Browse files
Added macOS and Tizen support
1 parent 27bf2bb commit 3a59f02

File tree

2 files changed

+354
-0
lines changed

2 files changed

+354
-0
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using Xamarin.Forms.Platform.MacOS;
2+
using AppKit;
3+
using Foundation;
4+
using Xamarin.Forms;
5+
using Xamarin.CommunityToolkit.macOS.Effects;
6+
using Xamarin.CommunityToolkit.Effects;
7+
8+
[assembly: ExportEffect(typeof(PlatformTouchEffect), nameof(TouchEffect))]
9+
10+
namespace Xamarin.CommunityToolkit.macOS.Effects
11+
{
12+
[Preserve(AllMembers = true)]
13+
public class PlatformTouchEffect : PlatformEffect
14+
{
15+
NSGestureRecognizer gesture;
16+
TouchEffect effect;
17+
MouseTrackingView mouseTrackingView;
18+
19+
protected override void OnAttached()
20+
{
21+
effect = TouchEffect.PickFrom(Element);
22+
if (effect?.IsDisabled ?? true)
23+
return;
24+
25+
effect.Control = Element as VisualElement;
26+
27+
if (Container != null)
28+
{
29+
gesture = new TouchNSClickGestureRecognizer(effect, Container);
30+
Container.AddGestureRecognizer(gesture);
31+
Container.AddSubview(mouseTrackingView = new MouseTrackingView(effect));
32+
}
33+
}
34+
35+
protected override void OnDetached()
36+
{
37+
if (effect?.Control == null)
38+
return;
39+
40+
mouseTrackingView?.RemoveFromSuperview();
41+
mouseTrackingView?.Dispose();
42+
mouseTrackingView = null;
43+
effect.Control = null;
44+
effect = null;
45+
if (gesture != null)
46+
Container?.RemoveGestureRecognizer(gesture);
47+
48+
gesture?.Dispose();
49+
gesture = null;
50+
}
51+
}
52+
53+
sealed class MouseTrackingView : NSView
54+
{
55+
NSTrackingArea trackingArea;
56+
TouchEffect effect;
57+
58+
public MouseTrackingView(TouchEffect effect)
59+
{
60+
this.effect = effect;
61+
AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable;
62+
}
63+
64+
public override void UpdateTrackingAreas()
65+
{
66+
if (trackingArea != null)
67+
{
68+
RemoveTrackingArea(trackingArea);
69+
trackingArea.Dispose();
70+
}
71+
trackingArea = new NSTrackingArea(Frame, NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveAlways, this, null);
72+
AddTrackingArea(trackingArea);
73+
}
74+
75+
public override void MouseEntered(NSEvent theEvent)
76+
{
77+
if (effect?.IsDisabled ?? true)
78+
return;
79+
80+
effect?.HandleHover(HoverStatus.Entered);
81+
}
82+
83+
public override void MouseExited(NSEvent theEvent)
84+
{
85+
if (effect?.IsDisabled ?? true)
86+
return;
87+
88+
effect?.HandleHover(HoverStatus.Exited);
89+
}
90+
91+
protected override void Dispose(bool disposing)
92+
{
93+
if (disposing)
94+
{
95+
if (trackingArea != null)
96+
{
97+
RemoveTrackingArea(trackingArea);
98+
trackingArea.Dispose();
99+
}
100+
effect = null;
101+
}
102+
base.Dispose(disposing);
103+
}
104+
}
105+
106+
sealed class TouchNSClickGestureRecognizer : NSGestureRecognizer
107+
{
108+
TouchEffect effect;
109+
NSView container;
110+
111+
public TouchNSClickGestureRecognizer(TouchEffect effect, NSView container)
112+
{
113+
this.effect = effect;
114+
this.container = container;
115+
}
116+
117+
Rectangle ViewRect
118+
{
119+
get
120+
{
121+
var frame = container.Frame;
122+
var parent = container.Superview;
123+
while (parent != null)
124+
{
125+
frame = new CoreGraphics.CGRect(frame.X + parent.Frame.X, frame.Y + parent.Frame.Y, frame.Width, frame.Height);
126+
parent = parent.Superview;
127+
}
128+
return frame.ToRectangle();
129+
}
130+
}
131+
132+
public override void MouseDown(NSEvent mouseEvent)
133+
{
134+
if (effect?.IsDisabled ?? true)
135+
return;
136+
137+
effect?.HandleUserInteraction(TouchInteractionStatus.Started);
138+
effect?.HandleTouch(TouchStatus.Started);
139+
base.MouseDown(mouseEvent);
140+
}
141+
142+
public override void MouseUp(NSEvent mouseEvent)
143+
{
144+
if (effect?.IsDisabled ?? true)
145+
return;
146+
147+
if (effect.HoverStatus == HoverStatus.Entered)
148+
{
149+
var touchPoint = mouseEvent.LocationInWindow.ToPoint();
150+
var status = ViewRect.Contains(touchPoint)
151+
? TouchStatus.Completed
152+
: TouchStatus.Canceled;
153+
154+
effect?.HandleTouch(status);
155+
}
156+
effect?.HandleUserInteraction(TouchInteractionStatus.Completed);
157+
158+
base.MouseUp(mouseEvent);
159+
}
160+
161+
public override void MouseDragged(NSEvent mouseEvent)
162+
{
163+
if (effect?.IsDisabled ?? true)
164+
return;
165+
166+
var status = ViewRect.Contains(mouseEvent.LocationInWindow.ToPoint()) ? TouchStatus.Started : TouchStatus.Canceled;
167+
168+
if ((status == TouchStatus.Canceled && effect.HoverStatus == HoverStatus.Entered) ||
169+
(status == TouchStatus.Started && effect.HoverStatus == HoverStatus.Exited))
170+
effect?.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited);
171+
172+
if (effect.Status != status)
173+
effect?.HandleTouch(status);
174+
175+
base.MouseDragged(mouseEvent);
176+
}
177+
178+
protected override void Dispose(bool disposing)
179+
{
180+
if (disposing)
181+
{
182+
effect = null;
183+
container = null;
184+
}
185+
base.Dispose(disposing);
186+
}
187+
}
188+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using ElmSharp;
2+
using Xamarin.Forms;
3+
using Xamarin.Forms.Internals;
4+
using Xamarin.Forms.Platform.Tizen;
5+
using Xamarin.CommunityToolkit.Tizen.Effects;
6+
using Xamarin.CommunityToolkit.Effects;
7+
using EColor = ElmSharp.Color;
8+
9+
[assembly: ExportEffect(typeof(PlatformTouchEffect), nameof(TouchEffect))]
10+
11+
namespace Xamarin.CommunityToolkit.Tizen.Effects
12+
{
13+
[Preserve(AllMembers = true)]
14+
public class PlatformTouchEffect : PlatformEffect
15+
{
16+
GestureLayer gestureLayer;
17+
TouchEffect effect;
18+
19+
protected override void OnAttached()
20+
{
21+
effect = TouchEffect.PickFrom(Element);
22+
if (effect?.IsDisabled ?? true)
23+
return;
24+
25+
effect.Control = Element as VisualElement;
26+
gestureLayer = new TouchTapGestureRecognizer(Control, effect);
27+
}
28+
29+
protected override void OnDetached()
30+
{
31+
if (effect?.Control == null)
32+
return;
33+
34+
if (gestureLayer != null)
35+
{
36+
gestureLayer.ClearCallbacks();
37+
gestureLayer.Unrealize();
38+
gestureLayer = null;
39+
}
40+
effect.Control = null;
41+
effect = null;
42+
}
43+
}
44+
45+
sealed class TouchTapGestureRecognizer : GestureLayer
46+
{
47+
readonly TouchEffect effect;
48+
bool tapCompleted;
49+
bool longTapStarted;
50+
51+
public TouchTapGestureRecognizer(EvasObject parent)
52+
: base(parent)
53+
{
54+
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Start, OnTapStarted);
55+
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.End, OnGestureEnded);
56+
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Abort, OnGestureAborted);
57+
58+
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Start, OnLongTapStarted);
59+
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.End, OnGestureEnded);
60+
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Abort, OnGestureAborted);
61+
}
62+
63+
public TouchTapGestureRecognizer(EvasObject parent, TouchEffect effect)
64+
: this(parent)
65+
{
66+
Attach(parent);
67+
this.effect = effect;
68+
}
69+
70+
public bool IsCanceled { get; set; } = true;
71+
72+
void OnTapStarted(TapData data)
73+
{
74+
if (effect?.IsDisabled ?? true)
75+
return;
76+
77+
IsCanceled = false;
78+
HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started);
79+
}
80+
81+
void OnLongTapStarted(TapData data)
82+
{
83+
if (effect?.IsDisabled ?? true)
84+
return;
85+
86+
IsCanceled = false;
87+
88+
longTapStarted = true;
89+
HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started);
90+
}
91+
92+
void OnGestureEnded(TapData data)
93+
{
94+
if (effect?.IsDisabled ?? true)
95+
return;
96+
97+
HandleTouch(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed);
98+
IsCanceled = true;
99+
tapCompleted = true;
100+
}
101+
102+
void OnGestureAborted(TapData data)
103+
{
104+
if (effect?.IsDisabled ?? true)
105+
return;
106+
107+
if (tapCompleted || longTapStarted)
108+
{
109+
tapCompleted = false;
110+
longTapStarted = false;
111+
return;
112+
}
113+
114+
HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed);
115+
IsCanceled = true;
116+
}
117+
118+
public void HandleTouch(TouchStatus status, TouchInteractionStatus? touchInteractionStatus = null)
119+
{
120+
if (IsCanceled || effect == null)
121+
return;
122+
123+
if (effect?.IsDisabled ?? true)
124+
return;
125+
126+
effect.HandleTouch(status);
127+
if (touchInteractionStatus.HasValue)
128+
effect.HandleUserInteraction(touchInteractionStatus.Value);
129+
130+
if (!effect.NativeAnimation)
131+
return;
132+
133+
if (longTapStarted && !tapCompleted)
134+
return;
135+
136+
var control = effect.Control;
137+
if (!(Platform.GetOrCreateRenderer(control)?.NativeView is Widget nativeView))
138+
return;
139+
140+
if (status == TouchStatus.Started)
141+
{
142+
var startColor = nativeView.BackgroundColor;
143+
if (startColor.IsDefault)
144+
return;
145+
146+
var endColor = effect.NativeAnimationColor.ToNative();
147+
if (endColor.IsDefault)
148+
{
149+
startColor = EColor.FromRgba(startColor.R, startColor.G, startColor.B, startColor.A / 2);
150+
endColor = startColor;
151+
}
152+
153+
var transit = new Transit
154+
{
155+
Repeat = 1,
156+
Duration = .2
157+
};
158+
var colorEffect = new ColorEffect(startColor, endColor);
159+
colorEffect.EffectEnded += (s, e) => { transit?.Dispose(); };
160+
transit.Objects.Add(nativeView);
161+
transit.AddEffect(colorEffect);
162+
transit.Go(.2);
163+
}
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)