Browse Source

remove event for querying text input options. replace with attached property that is inheritable.

pull/7781/head
Dan Walmsley 5 years ago
parent
commit
409be7f33f
  1. 3
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  2. 6
      samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
  3. 4
      src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs
  4. 8
      src/Avalonia.Input/ApiCompatBaseline.txt
  5. 17
      src/Avalonia.Input/InputElement.cs
  6. 1
      src/Avalonia.Input/Properties/AssemblyInfo.cs
  7. 2
      src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs
  8. 31
      src/Avalonia.Input/TextInput/InputMethodManager.cs
  9. 37
      src/Avalonia.Input/TextInput/TextInputOptions.cs
  10. 71
      src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs

3
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -18,7 +18,7 @@
</TextBox.ContextFlyout> </TextBox.ContextFlyout>
</TextBox> </TextBox>
<TextBox Width="200" Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/> <TextBox Width="200" Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
<TextBox Width="200" Watermark="Numeric with watermark" x:Name="numericWatermark"/> <TextBox Width="200" Watermark="Numeric with watermark" TextInputOptions.ContentType="Number" />
<TextBox Width="200" <TextBox Width="200"
Watermark="Floating Watermark" Watermark="Floating Watermark"
UseFloatingWatermark="True" UseFloatingWatermark="True"
@ -34,6 +34,7 @@
<TextBox Width="200" <TextBox Width="200"
Watermark="Password Box" Watermark="Password Box"
Classes="revealPasswordButton" Classes="revealPasswordButton"
TextInputOptions.ContentType="Password"
UseFloatingWatermark="True" UseFloatingWatermark="True"
PasswordChar="*" PasswordChar="*"
Text="Password" /> Text="Password" />

6
samples/ControlCatalog/Pages/TextBoxPage.xaml.cs

@ -13,12 +13,6 @@ namespace ControlCatalog.Pages
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
this.Get<TextBox>("numericWatermark")
.TextInputOptionsQuery += (s, a) =>
{
a.ContentType = Avalonia.Input.TextInput.TextInputContentType.Number;
};
} }
} }
} }

4
src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs

@ -198,9 +198,9 @@ namespace Avalonia.FreeDesktop.DBusIme
UpdateActive(); UpdateActive();
} }
void ITextInputMethodImpl.SetActive(bool active) void ITextInputMethodImpl.SetActive(ITextInputMethodClient client)
{ {
_controlActive = active; _controlActive = client is { };
UpdateActive(); UpdateActive();
} }

8
src/Avalonia.Input/ApiCompatBaseline.txt

@ -4,11 +4,17 @@ MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.In
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.Gestures.RightTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.Gestures.RightTappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.Gestures.TappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.Gestures.TappedEvent' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.RemoveFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.RemoveFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs> Avalonia.Input.InputElement.TextInputOptionsQueryEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.InputElement.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.InputElement.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.InputElement.TappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Interactivity.RoutedEventArgs> Avalonia.Input.InputElement.TappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_DoubleTapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_DoubleTapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_Tapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_Tapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_TextInputOptionsQuery(System.EventHandler<Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_DoubleTapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_DoubleTapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_Tapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_Tapped(System.EventHandler<Avalonia.Interactivity.RoutedEventArgs>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_TextInputOptionsQuery(System.EventHandler<Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs>)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(Avalonia.Input.TextInput.ITextInputMethodClient)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(System.Boolean)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(System.Boolean)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Platform.IStandardCursorFactory' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Platform.IStandardCursorFactory' does not exist in the implementation but it does exist in the contract.
Total Issues: 12 Total Issues: 18

17
src/Avalonia.Input/InputElement.cs

@ -126,14 +126,6 @@ namespace Avalonia.Input
RoutedEvent.Register<InputElement, TextInputMethodClientRequestedEventArgs>( RoutedEvent.Register<InputElement, TextInputMethodClientRequestedEventArgs>(
"TextInputMethodClientRequested", "TextInputMethodClientRequested",
RoutingStrategies.Tunnel | RoutingStrategies.Bubble); RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="TextInputOptionsQuery"/> event.
/// </summary>
public static readonly RoutedEvent<TextInputOptionsQueryEventArgs> TextInputOptionsQueryEvent =
RoutedEvent.Register<InputElement, TextInputOptionsQueryEventArgs>(
"TextInputOptionsQuery",
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
/// <summary> /// <summary>
/// Defines the <see cref="PointerEnter"/> event. /// Defines the <see cref="PointerEnter"/> event.
@ -283,15 +275,6 @@ namespace Avalonia.Input
add { AddHandler(TextInputMethodClientRequestedEvent, value); } add { AddHandler(TextInputMethodClientRequestedEvent, value); }
remove { RemoveHandler(TextInputMethodClientRequestedEvent, value); } remove { RemoveHandler(TextInputMethodClientRequestedEvent, value); }
} }
/// <summary>
/// Occurs when an input element gains input focus and input method is asking for required content options
/// </summary>
public event EventHandler<TextInputOptionsQueryEventArgs>? TextInputOptionsQuery
{
add { AddHandler(TextInputOptionsQueryEvent, value); }
remove { RemoveHandler(TextInputOptionsQueryEvent, value); }
}
/// <summary> /// <summary>
/// Occurs when the pointer enters the control. /// Occurs when the pointer enters the control.

1
src/Avalonia.Input/Properties/AssemblyInfo.cs

@ -2,4 +2,5 @@ using System.Reflection;
using Avalonia.Metadata; using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input.TextInput")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input.GestureRecognizers")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input.GestureRecognizers")]

2
src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs

@ -2,7 +2,7 @@ namespace Avalonia.Input.TextInput
{ {
public interface ITextInputMethodImpl public interface ITextInputMethodImpl
{ {
void SetActive(bool active); void SetActive(ITextInputMethodClient? client);
void SetCursorRect(Rect rect); void SetCursorRect(Rect rect);
void SetOptions(TextInputOptionsQueryEventArgs options); void SetOptions(TextInputOptionsQueryEventArgs options);
void Reset(); void Reset();

31
src/Avalonia.Input/TextInput/InputMethodManager.cs

@ -35,21 +35,25 @@ namespace Avalonia.Input.TextInput
{ {
_client.CursorRectangleChanged += OnCursorRectangleChanged; _client.CursorRectangleChanged += OnCursorRectangleChanged;
_client.TextViewVisualChanged += OnTextViewVisualChanged; _client.TextViewVisualChanged += OnTextViewVisualChanged;
var optionsQuery = new TextInputOptionsQueryEventArgs
{
RoutedEvent = InputElement.TextInputOptionsQueryEvent
};
_focusedElement?.RaiseEvent(optionsQuery);
_im?.Reset(); _im?.Reset();
_im?.SetOptions(optionsQuery);
_transformTracker?.SetVisual(_client?.TextViewVisual); if (_focusedElement is AvaloniaObject target)
{
var options =
new TextInputOptionsQueryEventArgs { ContentType = TextInputOptions.GetContentType(target) };
_im?.SetOptions(options);
}
_transformTracker.SetVisual(_client?.TextViewVisual);
UpdateCursorRect(); UpdateCursorRect();
_im?.SetActive(true); _im?.SetActive(_client);
} }
else else
{ {
_im?.SetActive(false); _im?.SetActive(null);
_transformTracker.SetVisual(null); _transformTracker.SetVisual(null);
} }
} }
@ -91,12 +95,15 @@ namespace Avalonia.Input.TextInput
_focusedElement = element; _focusedElement = element;
var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod; var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
if (_im != inputMethod)
_im?.SetActive(false);
_im = inputMethod; _im = inputMethod;
TryFindAndApplyClient(); TryFindAndApplyClient();
if (_im != inputMethod)
{
_im?.SetActive(Client);
}
} }
private void TryFindAndApplyClient() private void TryFindAndApplyClient()

37
src/Avalonia.Input/TextInput/TextInputOptions.cs

@ -0,0 +1,37 @@
namespace Avalonia.Input.TextInput;
public class TextInputOptions
{
/// <summary>
/// Defines the <see cref="ContentType"/> property.
/// </summary>
public static readonly AttachedProperty<TextInputContentType> ContentTypeProperty =
AvaloniaProperty.RegisterAttached<TextInputOptions, AvaloniaObject, TextInputContentType>(
"ContentType",
defaultValue: TextInputContentType.Normal,
inherits: true);
/// <summary>
/// Sets the value of the attached <see cref="ContentTypeProperty"/> on a control.
/// </summary>
/// <param name="avaloniaObject">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetContentType(AvaloniaObject avaloniaObject, TextInputContentType value)
{
avaloniaObject.SetValue(ContentTypeProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="ContentTypeProperty"/> on a control.
/// </summary>
/// <param name="avaloniaObject">The control.</param>
/// <returns>The font family.</returns>
public static TextInputContentType GetContentType(AvaloniaObject avaloniaObject)
{
return avaloniaObject.GetValue(ContentTypeProperty);
}
}

71
src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs

@ -1,20 +1,41 @@
using Foundation; using Foundation;
using ObjCRuntime; using ObjCRuntime;
using UIKit;
using Avalonia.Input.TextInput; using Avalonia.Input.TextInput;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using UIKit;
namespace Avalonia.iOS; namespace Avalonia.iOS;
#nullable enable
[Adopts("UITextInputTraits")]
[Adopts("UIKeyInput")] [Adopts("UIKeyInput")]
public partial class AvaloniaView : ITextInputMethodImpl public partial class AvaloniaView : ITextInputMethodImpl
{ {
private ITextInputMethodClient? _currentClient;
public override bool CanResignFirstResponder => true; public override bool CanResignFirstResponder => true;
public override bool CanBecomeFirstResponder => true; public override bool CanBecomeFirstResponder => true;
public override bool CanBecomeFocused => true;
[Export("hasText")] public bool HasText => false; [Export("hasText")]
public bool HasText
{
get
{
if (_currentClient is { } && _currentClient.SupportsSurroundingText &&
_currentClient.SurroundingText.Text.Length > 0)
{
return true;
}
return false;
}
}
[Export("keyboardType")] public UIKeyboardType KeyboardType { get; private set; } = UIKeyboardType.Default;
[Export("isSecureTextEntry")] public bool IsSecureEntry { get; private set; }
[Export("insertText:")] [Export("insertText:")]
public void InsertText(string text) public void InsertText(string text)
@ -24,7 +45,6 @@ public partial class AvaloniaView : ITextInputMethodImpl
_topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance, _topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance,
0, InputRoot, text)); 0, InputRoot, text));
} }
} }
[Export("deleteBackward")] [Export("deleteBackward")]
@ -41,13 +61,13 @@ public partial class AvaloniaView : ITextInputMethodImpl
} }
} }
void ITextInputMethodImpl.SetActive(bool active) void ITextInputMethodImpl.SetActive(ITextInputMethodClient? client)
{ {
if (active) _currentClient = client;
if (client is { })
{ {
var isFr = IsFirstResponder; BecomeFirstResponder();
var next = NextResponder;
var result = BecomeFirstResponder();
} }
else else
{ {
@ -57,16 +77,43 @@ public partial class AvaloniaView : ITextInputMethodImpl
void ITextInputMethodImpl.SetCursorRect(Rect rect) void ITextInputMethodImpl.SetCursorRect(Rect rect)
{ {
} }
void ITextInputMethodImpl.SetOptions(TextInputOptionsQueryEventArgs options) void ITextInputMethodImpl.SetOptions(TextInputOptionsQueryEventArgs options)
{ {
switch (options.ContentType)
{
case TextInputContentType.Email:
KeyboardType = UIKeyboardType.EmailAddress;
break;
case TextInputContentType.Number:
KeyboardType = UIKeyboardType.NumberPad;
break;
case TextInputContentType.Password:
IsSecureEntry = true;
break;
case TextInputContentType.Phone:
KeyboardType = UIKeyboardType.PhonePad;
break;
case TextInputContentType.Url:
KeyboardType = UIKeyboardType.Url;
break;
case TextInputContentType.Normal:
KeyboardType = UIKeyboardType.Default;
break;
}
} }
void ITextInputMethodImpl.Reset() void ITextInputMethodImpl.Reset()
{ {
IsSecureEntry = false;
KeyboardType = UIKeyboardType.Default;
ResignFirstResponder();
} }
} }

Loading…
Cancel
Save