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 Perspex.Controls.Platform; using Perspex.Input; using Perspex.Input.Raw; using Perspex.Media; using Perspex.Platform; using Perspex.Skia.iOS; using UIKit; using Perspex.iOS.Specific; using ObjCRuntime; using Perspex.Controls; namespace Perspex.iOS { [Adopts("UIKeyInput")] class PerspexView : SkiaView, IWindowImpl { private readonly UIWindow _window; private readonly UIViewController _controller; private IInputRoot _inputRoot; private readonly KeyboardEventsHelper _keyboardHelper; public PerspexView(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(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 Input { get; set; } public Action Paint { get; set; } public Action Resized { get; set; } public Action ScalingChanged { get; set; } public IPlatformHandle Handle => PerspexPlatformHandle; public double Scaling => 1; public WindowState WindowState { get { return WindowState.Normal; } set { } } public override void LayoutSubviews() => Resized?.Invoke(ClientSize); public Size ClientSize { get { return Bounds.Size.ToPerspex(); } 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; set; } public Size MaxClientSize => Bounds.Size.ToPerspex(); 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).ToPerspex(); Input?.Invoke(new RawMouseEventArgs( PerspexAppDelegate.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).ToPerspex(); _touchLastPoint = location; Input?.Invoke(new RawMouseEventArgs(PerspexAppDelegate.MouseDevice, (uint) touch.Timestamp, _inputRoot, RawMouseEventType.Move, location, InputModifiers.None)); Input?.Invoke(new RawMouseEventArgs(PerspexAppDelegate.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).ToPerspex(); if (PerspexAppDelegate.MouseDevice.Captured != null) Input?.Invoke(new RawMouseEventArgs(PerspexAppDelegate.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(PerspexAppDelegate.MouseDevice, (uint)touch.Timestamp, _inputRoot, location, (location - _touchLastPoint)* correction, InputModifiers.LeftMouseButton)); } _touchLastPoint = location; } } } class PerspexViewController : UIViewController { public PerspexView PerspexView { get; } public PerspexViewController(UIWindow window) { PerspexView = new PerspexView(window, this); } public override void LoadView() { View = PerspexView; } } }