This repository has been archived by the owner on May 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 469
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
27bf2bb
commit 3a59f02
Showing
2 changed files
with
354 additions
and
0 deletions.
There are no files selected for viewing
188 changes: 188 additions & 0 deletions
188
XamarinCommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
using Xamarin.Forms.Platform.MacOS; | ||
using AppKit; | ||
using Foundation; | ||
using Xamarin.Forms; | ||
using Xamarin.CommunityToolkit.macOS.Effects; | ||
using Xamarin.CommunityToolkit.Effects; | ||
|
||
[assembly: ExportEffect(typeof(PlatformTouchEffect), nameof(TouchEffect))] | ||
|
||
namespace Xamarin.CommunityToolkit.macOS.Effects | ||
{ | ||
[Preserve(AllMembers = true)] | ||
public class PlatformTouchEffect : PlatformEffect | ||
{ | ||
NSGestureRecognizer gesture; | ||
TouchEffect effect; | ||
MouseTrackingView mouseTrackingView; | ||
|
||
protected override void OnAttached() | ||
{ | ||
effect = TouchEffect.PickFrom(Element); | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect.Control = Element as VisualElement; | ||
|
||
if (Container != null) | ||
{ | ||
gesture = new TouchNSClickGestureRecognizer(effect, Container); | ||
Container.AddGestureRecognizer(gesture); | ||
Container.AddSubview(mouseTrackingView = new MouseTrackingView(effect)); | ||
} | ||
} | ||
|
||
protected override void OnDetached() | ||
{ | ||
if (effect?.Control == null) | ||
return; | ||
|
||
mouseTrackingView?.RemoveFromSuperview(); | ||
mouseTrackingView?.Dispose(); | ||
mouseTrackingView = null; | ||
effect.Control = null; | ||
effect = null; | ||
if (gesture != null) | ||
Container?.RemoveGestureRecognizer(gesture); | ||
|
||
gesture?.Dispose(); | ||
gesture = null; | ||
} | ||
} | ||
|
||
sealed class MouseTrackingView : NSView | ||
{ | ||
NSTrackingArea trackingArea; | ||
TouchEffect effect; | ||
|
||
public MouseTrackingView(TouchEffect effect) | ||
{ | ||
this.effect = effect; | ||
AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable; | ||
} | ||
|
||
public override void UpdateTrackingAreas() | ||
{ | ||
if (trackingArea != null) | ||
{ | ||
RemoveTrackingArea(trackingArea); | ||
trackingArea.Dispose(); | ||
} | ||
trackingArea = new NSTrackingArea(Frame, NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveAlways, this, null); | ||
AddTrackingArea(trackingArea); | ||
} | ||
|
||
public override void MouseEntered(NSEvent theEvent) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect?.HandleHover(HoverStatus.Entered); | ||
} | ||
|
||
public override void MouseExited(NSEvent theEvent) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect?.HandleHover(HoverStatus.Exited); | ||
} | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
if (trackingArea != null) | ||
{ | ||
RemoveTrackingArea(trackingArea); | ||
trackingArea.Dispose(); | ||
} | ||
effect = null; | ||
} | ||
base.Dispose(disposing); | ||
} | ||
} | ||
|
||
sealed class TouchNSClickGestureRecognizer : NSGestureRecognizer | ||
{ | ||
TouchEffect effect; | ||
NSView container; | ||
|
||
public TouchNSClickGestureRecognizer(TouchEffect effect, NSView container) | ||
{ | ||
this.effect = effect; | ||
this.container = container; | ||
} | ||
|
||
Rectangle ViewRect | ||
{ | ||
get | ||
{ | ||
var frame = container.Frame; | ||
var parent = container.Superview; | ||
while (parent != null) | ||
{ | ||
frame = new CoreGraphics.CGRect(frame.X + parent.Frame.X, frame.Y + parent.Frame.Y, frame.Width, frame.Height); | ||
parent = parent.Superview; | ||
} | ||
return frame.ToRectangle(); | ||
} | ||
} | ||
|
||
public override void MouseDown(NSEvent mouseEvent) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect?.HandleUserInteraction(TouchInteractionStatus.Started); | ||
effect?.HandleTouch(TouchStatus.Started); | ||
base.MouseDown(mouseEvent); | ||
} | ||
|
||
public override void MouseUp(NSEvent mouseEvent) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
if (effect.HoverStatus == HoverStatus.Entered) | ||
{ | ||
var touchPoint = mouseEvent.LocationInWindow.ToPoint(); | ||
var status = ViewRect.Contains(touchPoint) | ||
? TouchStatus.Completed | ||
: TouchStatus.Canceled; | ||
|
||
effect?.HandleTouch(status); | ||
} | ||
effect?.HandleUserInteraction(TouchInteractionStatus.Completed); | ||
|
||
base.MouseUp(mouseEvent); | ||
} | ||
|
||
public override void MouseDragged(NSEvent mouseEvent) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
var status = ViewRect.Contains(mouseEvent.LocationInWindow.ToPoint()) ? TouchStatus.Started : TouchStatus.Canceled; | ||
|
||
if ((status == TouchStatus.Canceled && effect.HoverStatus == HoverStatus.Entered) || | ||
(status == TouchStatus.Started && effect.HoverStatus == HoverStatus.Exited)) | ||
effect?.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited); | ||
|
||
if (effect.Status != status) | ||
effect?.HandleTouch(status); | ||
|
||
base.MouseDragged(mouseEvent); | ||
} | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
effect = null; | ||
container = null; | ||
} | ||
base.Dispose(disposing); | ||
} | ||
} | ||
} |
166 changes: 166 additions & 0 deletions
166
XamarinCommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
using ElmSharp; | ||
using Xamarin.Forms; | ||
using Xamarin.Forms.Internals; | ||
using Xamarin.Forms.Platform.Tizen; | ||
using Xamarin.CommunityToolkit.Tizen.Effects; | ||
using Xamarin.CommunityToolkit.Effects; | ||
using EColor = ElmSharp.Color; | ||
|
||
[assembly: ExportEffect(typeof(PlatformTouchEffect), nameof(TouchEffect))] | ||
|
||
namespace Xamarin.CommunityToolkit.Tizen.Effects | ||
{ | ||
[Preserve(AllMembers = true)] | ||
public class PlatformTouchEffect : PlatformEffect | ||
{ | ||
GestureLayer gestureLayer; | ||
TouchEffect effect; | ||
|
||
protected override void OnAttached() | ||
{ | ||
effect = TouchEffect.PickFrom(Element); | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect.Control = Element as VisualElement; | ||
gestureLayer = new TouchTapGestureRecognizer(Control, effect); | ||
} | ||
|
||
protected override void OnDetached() | ||
{ | ||
if (effect?.Control == null) | ||
return; | ||
|
||
if (gestureLayer != null) | ||
{ | ||
gestureLayer.ClearCallbacks(); | ||
gestureLayer.Unrealize(); | ||
gestureLayer = null; | ||
} | ||
effect.Control = null; | ||
effect = null; | ||
} | ||
} | ||
|
||
sealed class TouchTapGestureRecognizer : GestureLayer | ||
{ | ||
readonly TouchEffect effect; | ||
bool tapCompleted; | ||
bool longTapStarted; | ||
|
||
public TouchTapGestureRecognizer(EvasObject parent) | ||
: base(parent) | ||
{ | ||
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Start, OnTapStarted); | ||
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.End, OnGestureEnded); | ||
SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Abort, OnGestureAborted); | ||
|
||
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Start, OnLongTapStarted); | ||
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.End, OnGestureEnded); | ||
SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Abort, OnGestureAborted); | ||
} | ||
|
||
public TouchTapGestureRecognizer(EvasObject parent, TouchEffect effect) | ||
: this(parent) | ||
{ | ||
Attach(parent); | ||
this.effect = effect; | ||
} | ||
|
||
public bool IsCanceled { get; set; } = true; | ||
|
||
void OnTapStarted(TapData data) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
IsCanceled = false; | ||
HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started); | ||
} | ||
|
||
void OnLongTapStarted(TapData data) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
IsCanceled = false; | ||
|
||
longTapStarted = true; | ||
HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started); | ||
} | ||
|
||
void OnGestureEnded(TapData data) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
HandleTouch(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed); | ||
IsCanceled = true; | ||
tapCompleted = true; | ||
} | ||
|
||
void OnGestureAborted(TapData data) | ||
{ | ||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
if (tapCompleted || longTapStarted) | ||
{ | ||
tapCompleted = false; | ||
longTapStarted = false; | ||
return; | ||
} | ||
|
||
HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed); | ||
IsCanceled = true; | ||
} | ||
|
||
public void HandleTouch(TouchStatus status, TouchInteractionStatus? touchInteractionStatus = null) | ||
{ | ||
if (IsCanceled || effect == null) | ||
return; | ||
|
||
if (effect?.IsDisabled ?? true) | ||
return; | ||
|
||
effect.HandleTouch(status); | ||
if (touchInteractionStatus.HasValue) | ||
effect.HandleUserInteraction(touchInteractionStatus.Value); | ||
|
||
if (!effect.NativeAnimation) | ||
return; | ||
|
||
if (longTapStarted && !tapCompleted) | ||
return; | ||
|
||
var control = effect.Control; | ||
if (!(Platform.GetOrCreateRenderer(control)?.NativeView is Widget nativeView)) | ||
return; | ||
|
||
if (status == TouchStatus.Started) | ||
{ | ||
var startColor = nativeView.BackgroundColor; | ||
if (startColor.IsDefault) | ||
return; | ||
|
||
var endColor = effect.NativeAnimationColor.ToNative(); | ||
if (endColor.IsDefault) | ||
{ | ||
startColor = EColor.FromRgba(startColor.R, startColor.G, startColor.B, startColor.A / 2); | ||
endColor = startColor; | ||
} | ||
|
||
var transit = new Transit | ||
{ | ||
Repeat = 1, | ||
Duration = .2 | ||
}; | ||
var colorEffect = new ColorEffect(startColor, endColor); | ||
colorEffect.EffectEnded += (s, e) => { transit?.Dispose(); }; | ||
transit.Objects.Add(nativeView); | ||
transit.AddEffect(colorEffect); | ||
transit.Go(.2); | ||
} | ||
} | ||
} | ||
} |