csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
7.8 KiB
249 lines
7.8 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Reactive.Disposables;
|
|
using System.Text;
|
|
using CoreAnimation;
|
|
using CoreGraphics;
|
|
using Foundation;
|
|
using Avalonia.Controls.Platform;
|
|
using Avalonia.Input;
|
|
using Avalonia.Input.Raw;
|
|
using Avalonia.Media;
|
|
using Avalonia.Platform;
|
|
using Avalonia.Skia.iOS;
|
|
using UIKit;
|
|
using Avalonia.iOS.Specific;
|
|
using ObjCRuntime;
|
|
using Avalonia.Controls;
|
|
|
|
namespace Avalonia.iOS
|
|
{
|
|
[Adopts("UIKeyInput")]
|
|
class AvaloniaView : SkiaView, IWindowImpl
|
|
{
|
|
private readonly UIWindow _window;
|
|
private readonly UIViewController _controller;
|
|
private IInputRoot _inputRoot;
|
|
private readonly KeyboardEventsHelper<AvaloniaView> _keyboardHelper;
|
|
private Point _position;
|
|
|
|
public AvaloniaView(UIWindow window, UIViewController controller) : base(onFrame => PlatformThreadingInterface.Instance.Render = onFrame)
|
|
{
|
|
if (controller == null) throw new ArgumentNullException(nameof(controller));
|
|
_window = window;
|
|
_controller = controller;
|
|
_keyboardHelper = new KeyboardEventsHelper<AvaloniaView>(this);
|
|
AutoresizingMask = UIViewAutoresizing.All;
|
|
AutoFit();
|
|
UIApplication.Notifications.ObserveDidChangeStatusBarOrientation(delegate { AutoFit(); });
|
|
UIApplication.Notifications.ObserveDidChangeStatusBarFrame(delegate { AutoFit(); });
|
|
}
|
|
|
|
[Export("hasText")]
|
|
bool HasText => _keyboardHelper.HasText();
|
|
|
|
[Export("insertText:")]
|
|
void InsertText(string text) => _keyboardHelper.InsertText(text);
|
|
|
|
[Export("deleteBackward")]
|
|
void DeleteBackward() => _keyboardHelper.DeleteBackward();
|
|
|
|
public override bool CanBecomeFirstResponder => _keyboardHelper.CanBecomeFirstResponder();
|
|
|
|
void AutoFit()
|
|
{
|
|
var needFlip = !UIDevice.CurrentDevice.CheckSystemVersion(8, 0) &&
|
|
(_controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft
|
|
|| _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeRight);
|
|
|
|
// Bounds here (if top level) needs to correspond with the rendertarget
|
|
var frame = UIScreen.MainScreen.Bounds;
|
|
if (needFlip)
|
|
Frame = new CGRect(frame.Y, frame.X, frame.Height, frame.Width);
|
|
else
|
|
Frame = frame;
|
|
}
|
|
|
|
public Action Activated { get; set; }
|
|
public Action Closed { get; set; }
|
|
public Action Deactivated { get; set; }
|
|
public Action<RawInputEventArgs> Input { get; set; }
|
|
public Action<Rect> Paint { get; set; }
|
|
public Action<Size> Resized { get; set; }
|
|
public Action<double> ScalingChanged { get; set; }
|
|
public Action<Point> PositionChanged { get; set; }
|
|
|
|
public IPlatformHandle Handle => AvaloniaPlatformHandle;
|
|
|
|
public double Scaling
|
|
{
|
|
get
|
|
{
|
|
// This does not appear to make any difference, but on iOS we
|
|
// have Retina (x2) and we probably want this eventually
|
|
return 1; //UIScreen.MainScreen.Scale;
|
|
}
|
|
}
|
|
|
|
public WindowState WindowState
|
|
{
|
|
get { return WindowState.Normal; }
|
|
set { }
|
|
}
|
|
|
|
public override void LayoutSubviews() => Resized?.Invoke(ClientSize);
|
|
|
|
public Size ClientSize
|
|
{
|
|
get { return Bounds.Size.ToAvalonia(); }
|
|
set { Resized?.Invoke(ClientSize); }
|
|
}
|
|
|
|
public void Activate()
|
|
{
|
|
}
|
|
|
|
protected override void Draw()
|
|
{
|
|
Paint?.Invoke(new Rect(new Point(), ClientSize));
|
|
}
|
|
|
|
public void Invalidate(Rect rect) => DrawOnNextFrame();
|
|
|
|
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
|
|
|
|
public Point PointToClient(Point point) => point;
|
|
|
|
public Point PointToScreen(Point point) => point;
|
|
|
|
public void SetCursor(IPlatformHandle cursor)
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public void Show()
|
|
{
|
|
_keyboardHelper.ActivateAutoShowKeybord();
|
|
}
|
|
|
|
public void BeginMoveDrag()
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public void BeginResizeDrag(WindowEdge edge)
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public Point Position
|
|
{
|
|
get { return _position; }
|
|
set
|
|
{
|
|
_position = value;
|
|
PositionChanged?.Invoke(_position);
|
|
}
|
|
}
|
|
|
|
public Size MaxClientSize => Bounds.Size.ToAvalonia();
|
|
|
|
public IEnumerable<object> Surfaces => new object[] { this };
|
|
|
|
public void SetTitle(string title)
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public IDisposable ShowDialog()
|
|
{
|
|
//Not supported
|
|
return Disposable.Empty;
|
|
}
|
|
|
|
public void Hide()
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public void SetSystemDecorations(bool enabled)
|
|
{
|
|
//Not supported
|
|
}
|
|
|
|
public override void TouchesEnded(NSSet touches, UIEvent evt)
|
|
{
|
|
var touch = touches.AnyObject as UITouch;
|
|
if (touch != null)
|
|
{
|
|
var location = touch.LocationInView(this).ToAvalonia();
|
|
|
|
Input?.Invoke(new RawMouseEventArgs(
|
|
iOSPlatform.MouseDevice,
|
|
(uint)touch.Timestamp,
|
|
_inputRoot,
|
|
RawMouseEventType.LeftButtonUp,
|
|
location,
|
|
InputModifiers.None));
|
|
}
|
|
}
|
|
|
|
Point _touchLastPoint;
|
|
public override void TouchesBegan(NSSet touches, UIEvent evt)
|
|
{
|
|
var touch = touches.AnyObject as UITouch;
|
|
if (touch != null)
|
|
{
|
|
var location = touch.LocationInView(this).ToAvalonia();
|
|
_touchLastPoint = location;
|
|
Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
|
|
RawMouseEventType.Move, location, InputModifiers.None));
|
|
|
|
Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
|
|
RawMouseEventType.LeftButtonDown, location, InputModifiers.None));
|
|
}
|
|
}
|
|
|
|
public override void TouchesMoved(NSSet touches, UIEvent evt)
|
|
{
|
|
var touch = touches.AnyObject as UITouch;
|
|
if (touch != null)
|
|
{
|
|
var location = touch.LocationInView(this).ToAvalonia();
|
|
if (iOSPlatform.MouseDevice.Captured != null)
|
|
Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
|
|
RawMouseEventType.Move, location, InputModifiers.LeftMouseButton));
|
|
else
|
|
{
|
|
//magic number based on test - correction of 0.02 is working perfect
|
|
double correction = 0.02;
|
|
|
|
Input?.Invoke(new RawMouseWheelEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp,
|
|
_inputRoot, location, (location - _touchLastPoint) * correction, InputModifiers.LeftMouseButton));
|
|
}
|
|
_touchLastPoint = location;
|
|
}
|
|
}
|
|
|
|
public void SetIcon(IWindowIconImpl icon)
|
|
{
|
|
}
|
|
}
|
|
|
|
class AvaloniaViewController : UIViewController
|
|
{
|
|
public AvaloniaView AvaloniaView { get; }
|
|
|
|
public AvaloniaViewController(UIWindow window)
|
|
{
|
|
AvaloniaView = new AvaloniaView(window, this);
|
|
}
|
|
|
|
public override void LoadView()
|
|
{
|
|
View = AvaloniaView;
|
|
}
|
|
}
|
|
}
|
|
|