Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PasswordChar support for TextBox #1544

Merged
merged 16 commits into from May 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 8 additions & 2 deletions samples/ControlCatalog/Pages/TextBoxPage.xaml
Expand Up @@ -10,10 +10,16 @@
<StackPanel Orientation="Vertical" Gap="8">
<TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
<TextBox Width="200" Watermark="Watermark" />
<TextBox Width="200"
Watermark="Floating Watermark"
<TextBox Width="200"
Watermark="Floating Watermark"
UseFloatingWatermark="True"
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>

<TextBox Width="200"
Watermark="Password Box"
UseFloatingWatermark="True"
PasswordChar="*"
Text="Password" />
<TextBox Width="200" Text="Left aligned text" TextAlignment="Left" />
<TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
<TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />
Expand Down
29 changes: 27 additions & 2 deletions src/Avalonia.Controls/Presenters/TextPresenter.cs
Expand Up @@ -17,6 +17,9 @@ public class TextPresenter : TextBlock
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);

public static readonly StyledProperty<char> PasswordCharProperty =
AvaloniaProperty.Register<TextPresenter, char>(nameof(PasswordChar));

public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
o => o.SelectionStart,
Expand Down Expand Up @@ -63,6 +66,12 @@ public int CaretIndex
}
}

public char PasswordChar
{
get => GetValue(PasswordCharProperty);
set => SetValue(PasswordCharProperty, value);
}

public int SelectionStart
{
get
Expand Down Expand Up @@ -202,9 +211,25 @@ internal void CaretIndexChanged(int caretIndex)
}
}

protected override FormattedText CreateFormattedText(Size constraint)
/// <summary>
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <param name="text">The text to generated the <see cref="FormattedText"/> for.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected override FormattedText CreateFormattedText(Size constraint, string text)
{
var result = base.CreateFormattedText(constraint);
FormattedText result = null;

if (PasswordChar != default(char))
{
result = base.CreateFormattedText(constraint, new string(PasswordChar, Text.Length));
}
else
{
result = base.CreateFormattedText(constraint, Text);
}

var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
var start = Math.Min(selectionStart, selectionEnd);
Expand Down
17 changes: 3 additions & 14 deletions src/Avalonia.Controls/Primitives/AccessText.cs
Expand Up @@ -78,21 +78,10 @@ public override void Render(DrawingContext context)
}
}

/// <summary>
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected override FormattedText CreateFormattedText(Size constraint)
/// <inheritdoc/>
protected override FormattedText CreateFormattedText(Size constraint, string text)
{
return new FormattedText
{
Constraint = constraint,
Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
Text = StripAccessKey(Text),
TextAlignment = TextAlignment,
Wrapping = TextWrapping,
};
return base.CreateFormattedText(constraint, StripAccessKey(text));
}

/// <summary>
Expand Down
7 changes: 4 additions & 3 deletions src/Avalonia.Controls/TextBlock.cs
Expand Up @@ -197,7 +197,7 @@ public FormattedText FormattedText
{
if (_formattedText == null)
{
_formattedText = CreateFormattedText(_constraint);
_formattedText = CreateFormattedText(_constraint, Text);
}

return _formattedText;
Expand Down Expand Up @@ -348,14 +348,15 @@ public override void Render(DrawingContext context)
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <param name="text">The text to format.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected virtual FormattedText CreateFormattedText(Size constraint)
protected virtual FormattedText CreateFormattedText(Size constraint, string text)
{
return new FormattedText
{
Constraint = constraint,
Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
Text = Text ?? string.Empty,
Text = text ?? string.Empty,
TextAlignment = TextAlignment,
Wrapping = TextWrapping,
};
Expand Down
35 changes: 26 additions & 9 deletions src/Avalonia.Controls/TextBox.cs
Expand Up @@ -30,10 +30,13 @@ public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.I
nameof(CaretIndex),
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);

public static readonly StyledProperty<bool> IsReadOnlyProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsReadOnly));

public static readonly StyledProperty<char> PasswordCharProperty =
AvaloniaProperty.Register<TextBox, char>(nameof(PasswordChar));

public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
AvaloniaProperty.RegisterDirect<TextBox, int>(
nameof(SelectionStart),
Expand Down Expand Up @@ -87,7 +90,7 @@ public UndoRedoState(string text, int caretPosition)
private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
private bool _isUndoingRedoing;
private bool _ignoreTextChanges;
private static readonly string[] invalidCharacters = new String[1]{"\u007f"};
private static readonly string[] invalidCharacters = new String[1] { "\u007f" };

static TextBox()
{
Expand Down Expand Up @@ -116,7 +119,7 @@ public TextBox()
ScrollViewer.HorizontalScrollBarVisibilityProperty,
horizontalScrollBarVisibility,
BindingPriority.Style);
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);
}

public bool AcceptsReturn
Expand Down Expand Up @@ -147,13 +150,19 @@ public int CaretIndex
_undoRedoHelper.UpdateLastState();
}
}

public bool IsReadOnly
{
get { return GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}

public char PasswordChar
{
get => GetValue(PasswordCharProperty);
set => SetValue(PasswordCharProperty, value);
}

public int SelectionStart
{
get
Expand Down Expand Up @@ -237,7 +246,7 @@ protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
_presenter.Cursor = new Cursor(StandardCursorType.Ibeam);

if(IsFocused)
if (IsFocused)
{
_presenter.ShowCaret();
}
Expand Down Expand Up @@ -349,16 +358,22 @@ protected override void OnKeyDown(KeyEventArgs e)
case Key.C:
if (modifiers == InputModifiers.Control)
{
Copy();
if (!IsPasswordBox)
{
Copy();
}
handled = true;
}
break;

case Key.X:
if (modifiers == InputModifiers.Control)
{
Copy();
DeleteSelection();
if (!IsPasswordBox)
{
Copy();
DeleteSelection();
}
handled = true;
}
break;
Expand Down Expand Up @@ -578,7 +593,7 @@ protected override void UpdateDataValidation(AvaloniaProperty property, BindingN
DataValidationErrors.SetError(this, status.Error);
}
}

private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text?.Length ?? 0);

private int CoerceCaretIndex(int value, int length)
Expand Down Expand Up @@ -856,6 +871,8 @@ private void SetSelectionForControlDelete(InputModifiers modifiers)
SelectionEnd = CaretIndex;
}

private bool IsPasswordBox => PasswordChar != default(char);

UndoRedoState UndoRedoHelper<UndoRedoState>.IUndoRedoHost.UndoRedoState
{
get { return new UndoRedoState(Text, CaretIndex); }
Expand Down
7 changes: 4 additions & 3 deletions src/Avalonia.Themes.Default/TextBox.xaml
Expand Up @@ -11,7 +11,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel Margin="{TemplateBinding Padding}">

<TextBlock Name="floatingWatermark"
Foreground="{DynamicResource ThemeAccentBrush}"
FontSize="{DynamicResource FontSizeSmall}"
Expand All @@ -31,7 +31,7 @@
<DataValidationErrors>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">

<Panel>
<TextBlock Name="watermark"
Opacity="0.5"
Expand All @@ -43,7 +43,8 @@
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}"/>
TextWrapping="{TemplateBinding TextWrapping}"
PasswordChar="{TemplateBinding PasswordChar}"/>
</Panel>
</ScrollViewer>
</DataValidationErrors>
Expand Down