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

Commit

Permalink
Added macOS and Tizen support
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreiMisiukevich committed Nov 18, 2020
1 parent 27bf2bb commit 3a59f02
Show file tree
Hide file tree
Showing 2 changed files with 354 additions and 0 deletions.
188 changes: 188 additions & 0 deletions XamarinCommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs
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 XamarinCommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs
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);
}
}
}
}

0 comments on commit 3a59f02

Please sign in to comment.