Przeglądaj źródła

make implementation consistent with ios sample.

https://developer.apple.com/library/archive/samplecode/SimpleTextInput/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010633
Dan Walmsley 3 lat temu
rodzic
commit
60381e290a
1 zmienionych plików z 106 dodań i 76 usunięć
  1. 106 76
      src/iOS/Avalonia.iOS/AvaloniaView.Text.cs

+ 106 - 76
src/iOS/Avalonia.iOS/AvaloniaView.Text.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Runtime.InteropServices;
 using Foundation;
 using ObjCRuntime;
 using Avalonia.Input.TextInput;
@@ -18,28 +19,33 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
 {
     private class AvaloniaTextRange : UITextRange
     {
-        private readonly AvaloniaTextPosition _start;
-        private readonly AvaloniaTextPosition _end;
+        private readonly NSRange _range;
 
-        public AvaloniaTextRange(int start, int end)
+        public AvaloniaTextRange(NSRange range)
         {
-            _start = new AvaloniaTextPosition(start);
-            _end = new AvaloniaTextPosition(end);
+            _range = range;
         }
 
-        public override AvaloniaTextPosition Start => _start;
+        public override AvaloniaTextPosition Start => new AvaloniaTextPosition((int)_range.Location);
 
-        public override AvaloniaTextPosition End => _end;
+        public override AvaloniaTextPosition End => new AvaloniaTextPosition((int)(_range.Location + _range.Length));
+
+        public NSRange Range => _range;
+
+        public override bool IsEmpty => _range.Length == 0;
     }
 
     private class AvaloniaTextPosition : UITextPosition
     {
-        public AvaloniaTextPosition(int offset)
+        public AvaloniaTextPosition(nint index)
         {
-            Offset = offset;
+            Index = index;
         }
 
-        public int Offset { get; }
+        public nint Index { get; }
+        
+        //[Export("inputDelegate")]
+        //public UITextInputDelegate InputDelegate { get; set; }
     }
 
     private string _markedText = "";
@@ -76,22 +82,25 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
             ResignFirstResponder();
         }
     }
+    
+    [DllImport("/usr/lib/libobjc.dylib")]
+    extern static void objc_msgSend(IntPtr receiver, IntPtr selector, IntPtr arg);
 
-    private void ClientOnSurroundingTextChanged(object? sender, EventArgs e)
+    private static readonly IntPtr SelectionWillChange = Selector.GetHandle("selectionWillChange:");
+    private static readonly IntPtr SelectionDidChange = Selector.GetHandle("selectionDidChange:");
+    private static readonly IntPtr TextWillChange = Selector.GetHandle("textWillChange:");
+    private static readonly IntPtr TextDidChange = Selector.GetHandle("textDidChange:");
+        
+    private void ClientOnCursorRectangleChanged(object? sender, EventArgs e)
     {
-        var _inputDelegate = UITextInputDelegate.FromObject(((IUITextInput)this).WeakInputDelegate) as IUITextInputDelegate;
-         
-        _inputDelegate?.TextWillChange(this);
-        _inputDelegate?.TextDidChange(this);
+        objc_msgSend(WeakInputDelegate.Handle.Handle, SelectionWillChange, this.Handle.Handle);
+        objc_msgSend(WeakInputDelegate.Handle.Handle, SelectionDidChange, this.Handle.Handle);
     }
 
-    private void ClientOnCursorRectangleChanged(object? sender, EventArgs e)
+    private void ClientOnSurroundingTextChanged(object? sender, EventArgs e)
     {
-        var _inputDelegate = Runtime.GetINativeObject<IUITextInputDelegate>(((IUITextInput)this).WeakInputDelegate.Handle.Handle, true);
-        
-        
-        _inputDelegate?.SelectionWillChange(this);
-        _inputDelegate?.SelectionDidChange(this);
+        objc_msgSend(WeakInputDelegate.Handle.Handle, TextWillChange, Handle.Handle);
+        objc_msgSend(WeakInputDelegate.Handle.Handle, TextDidChange, Handle.Handle);
     }
 
     void ITextInputMethodImpl.SetCursorRect(Rect rect)
@@ -255,8 +264,8 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
             text = text[.. cursorPos] + _markedText + text[cursorPos ..];
         }
 
-        var start = (range.Start as AvaloniaTextPosition).Offset;
-        int end = (range.End as AvaloniaTextPosition).Offset;
+        var start = (int)(range.Start as AvaloniaTextPosition).Index;
+        var end = (int)(range.End as AvaloniaTextPosition).Index;
 
         var result = text[start .. end];
 
@@ -298,7 +307,8 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
         if (fromPosition is AvaloniaTextPosition f && toPosition is AvaloniaTextPosition t)
         {
             // todo check calculation.
-            return new AvaloniaTextRange(f.Offset, t.Offset);
+            var range = new NSRange(Math.Min(f.Index, t.Index), Math.Abs(t.Index - f.Index));
+            return new AvaloniaTextRange(range);
         }
 
         throw new Exception();
@@ -306,18 +316,15 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
 
     UITextPosition IUITextInput.GetPosition(UITextPosition fromPosition, nint offset)
     {
-        if (fromPosition is AvaloniaTextPosition f)
+        if (fromPosition is AvaloniaTextPosition indexedPosition)
         {
-            var position = f.Offset;
-            int posPlusIndex = position + (int)offset;
-            var length = _client.SurroundingText.Text.Length;
+            var end = indexedPosition.Index + offset;
+            // Verify position is valid in document.
+            //if (end > self.text.length || end < 0) {
+            //    return nil;
+            //}
 
-            if (posPlusIndex < 0 || posPlusIndex > length)
-            {
-                return null;
-            }
-
-            return new AvaloniaTextPosition(posPlusIndex);
+            return new AvaloniaTextPosition(end);
         }
 
         return null;
@@ -327,19 +334,30 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
     {
         if (fromPosition is AvaloniaTextPosition f)
         {
-            var pos = f.Offset;
+            var newPosition = f.Index;
 
             switch (inDirection)
             {
                 case UITextLayoutDirection.Left:
-                    return new AvaloniaTextPosition(pos - (int)offset);
+                    newPosition -= offset;
+                    break;
 
                 case UITextLayoutDirection.Right:
-                    return new AvaloniaTextPosition(pos + (int)offset);
+                    newPosition += offset;
+                    break;
+            }
+
+            if (newPosition < 0)
+            {
+                newPosition = 0;
+            }
 
-                default:
-                    return fromPosition;
+            if (newPosition > _client.SurroundingText.Text.Length)
+            {
+                newPosition = _client.SurroundingText.Text.Length;
             }
+
+            return new AvaloniaTextPosition(newPosition);
         }
 
         throw new Exception();
@@ -349,28 +367,23 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
     {
         if (first is AvaloniaTextPosition f && second is AvaloniaTextPosition s)
         {
-            if (f.Offset > s.Offset)
+            if (f.Index < s.Index)
                 return NSComparisonResult.Ascending;
 
-            if (f.Offset < s.Offset)
+            if (f.Index > s.Index)
                 return NSComparisonResult.Descending;
 
             return NSComparisonResult.Same;
         }
 
-        return NSComparisonResult.Descending;
+        throw new Exception();
     }
 
     nint IUITextInput.GetOffsetFromPosition(UITextPosition fromPosition, UITextPosition toPosition)
     {
-        if (fromPosition is AvaloniaTextPosition f)
+        if (fromPosition is AvaloniaTextPosition f && toPosition is AvaloniaTextPosition t)
         {
-            if (toPosition is AvaloniaTextPosition t)
-            {
-                return t.Offset - f.Offset;
-            }
-
-            return f.Offset;
+            return t.Index - f.Index;
         }
 
         throw new Exception();
@@ -378,16 +391,24 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
 
     UITextPosition IUITextInput.GetPositionWithinRange(UITextRange range, UITextLayoutDirection direction)
     {
-        if (range is AvaloniaTextRange r)
+        if (range is AvaloniaTextRange indexedRange)
         {
+            nint position = 0;
+            
             switch (direction)
             {
+                case UITextLayoutDirection.Up:
+                case UITextLayoutDirection.Left:
+                    position = indexedRange.Range.Location;
+                    break;
+                
+                case UITextLayoutDirection.Down:
                 case UITextLayoutDirection.Right:
-                    return r.End;
-
-                default:
-                    return r.Start;
+                    position = indexedRange.Range.Location + indexedRange.Range.Length;
+                    break;
             }
+
+            return new AvaloniaTextPosition(position);
         }
 
         throw new Exception();
@@ -395,17 +416,24 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
 
     UITextRange IUITextInput.GetCharacterRange(UITextPosition byExtendingPosition, UITextLayoutDirection direction)
     {
-        if (byExtendingPosition is AvaloniaTextPosition p)
+        if (byExtendingPosition is AvaloniaTextPosition pos)
         {
+            NSRange result = new NSRange();
+            
             switch (direction)
             {
+                case UITextLayoutDirection.Up:
                 case UITextLayoutDirection.Left:
-                    return new AvaloniaTextRange(0, p.Offset);
+                    result = new NSRange(pos.Index - 1, 1);
+                    break;
 
-                default:
-                    // todo check this.
-                    return new AvaloniaTextRange(p.Offset, _client.SurroundingText.Text.Length);
+                case UITextLayoutDirection.Right:
+                case UITextLayoutDirection.Down:
+                    result = new NSRange(pos.Index, 1);
+                    break;
             }
+
+            return new AvaloniaTextRange(result);
         }
 
         throw new Exception();
@@ -464,23 +492,27 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
 
     UITextRange IUITextInput.GetCharacterRangeAtPoint(CGPoint point)
     {
-        // TODO check if needed, hittest?
-        return new AvaloniaTextRange(_client.SurroundingText.CursorOffset, _client.SurroundingText.CursorOffset);
+        return null;
     }
 
     UITextSelectionRect[] IUITextInput.GetSelectionRects(UITextRange range)
     {
-        // todo?
-        return Array.Empty<UITextSelectionRect>();
+        return null;
+    }
+
+    [Export("textStylingAtPosition:inDirection:")]
+    public NSDictionary GetTextStylingAtPosition(UITextPosition position, UITextStorageDirection direction)
+    {
+        return null;
     }
 
     UITextRange? IUITextInput.SelectedTextRange
     {
         get
         {
-            return new AvaloniaTextRange(
-                Math.Min(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset),
-                Math.Max(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset));
+            return new AvaloniaTextRange(new NSRange(
+                (nint)Math.Min(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset),
+                (nint)Math.Abs(_client.SurroundingText.CursorOffset - _client.SurroundingText.AnchorOffset)));
         }
         set
         {
@@ -504,8 +536,8 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
         }
     }
 
-    
-    NSObject? IUITextInput.WeakInputDelegate
+
+    public NSObject? WeakInputDelegate
     {
         get;
         set;
@@ -517,17 +549,15 @@ public partial class AvaloniaView : ITextInputMethodImpl, IUITextInput
     {
         get
         {
-            if (string.IsNullOrWhiteSpace(_markedText))
-            {
-                //return null;
-            }
-
-            if (_client == null)
+            if (_client == null || string.IsNullOrWhiteSpace(_markedText))
             {
                 return null;
             }
-            
-            return new AvaloniaTextRange(Math.Min(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset), Math.Max(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset));            
+
+            // todo
+            return new AvaloniaTextRange(new NSRange(
+                (nint)Math.Min(_client.SurroundingText.CursorOffset, _client.SurroundingText.AnchorOffset),
+                (nint)Math.Abs(_client.SurroundingText.CursorOffset - _client.SurroundingText.AnchorOffset)));            
         }
     }
 }