Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Support ChacaracterCasing in TextBox

Open cesarchefinho opened this issue 1 year ago • 8 comments

Is your feature request related to a problem? Please describe. Fix character casing on TextBoxes.

ALL FRAMEWORKS have it. (WInUI / UWP / WPF / WinForms)

Describe the solution you'd like

control how characters are cased when they are manually entered into the text box.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context

basicaly:

Add an enum

**public enum CharacterCasing
{
    Normal = 0,
    Upper,
    Lower
}**

modify textbox.cs

        **public static readonly StyledProperty<CharacterCasing> CharacterCasingProperty =
            AvaloniaProperty.Register<TextBox, CharacterCasing>(nameof(CharacterCasing));**

        **private string? AdjustCasing(string? text)
        {
            return CharacterCasing switch
            {
                CharacterCasing.Lower => text?.ToLower(),
                CharacterCasing.Upper => text?.ToUpper(),
                CharacterCasing.Normal => text,
                _ => text
            };
        }**

        **public CharacterCasing CharacterCasing
        {
            get => GetValue(CharacterCasingProperty);
            set => SetValue(CharacterCasingProperty, value);
        }**

        /// <summary>
        /// Gets or sets the Text content of the TextBox
        /// </summary>
        **[Content]
        public string? Text
        {
            get => AdjustCasing(GetValue(TextProperty));
            set => SetValue(TextProperty, AdjustCasing (value));
        }**

        protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
        {
            base.OnPropertyChanged(change);

            if (change.Property == TextProperty)
            {
                CoerceValue(CaretIndexProperty);
                CoerceValue(SelectionStartProperty);
                CoerceValue(SelectionEndProperty);

                RaiseTextChangeEvents();

                UpdatePseudoclasses();
                UpdateCommandStates();
            }
            **else if (change.Property == CharacterCasingProperty)
            {
                Text = AdjustCasing(Text);
            }**
            else if (change.Property == CaretIndexProperty)
            {
                OnCaretIndexChanged(change);
            }
            else if (change.Property == SelectionStartProperty)
            {
                OnSelectionStartChanged(change);
            }
            else if (change.Property == SelectionEndProperty)
            {
                OnSelectionEndChanged(change);
            }
            else if (change.Property == MaxLinesProperty)
            {
                InvalidateMeasure();
            }
            else if (change.Property == UndoLimitProperty)
            {
                OnUndoLimitChanged(change.GetNewValue<int>());
            }
            else if (change.Property == IsUndoEnabledProperty && change.GetNewValue<bool>() == false)
            {
                // from docs at
                // https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.textboxbase.isundoenabled:
                // "Setting this property to false clears the undo stack.
                // Therefore, if you disable undo and then re-enable it, undo commands still do not work
                // because the undo stack was emptied when you disabled undo."
                _undoRedoHelper.Clear();
                _selectedTextChangesMadeSinceLastUndoSnapshot = 0;
                _hasDoneSnapshotOnce = false;
            }
        }

        private void HandleTextInput(string? input)
        {
            if (IsReadOnly)
            {
                return;
            }
        
            **input = AdjustCasing(RemoveInvalidCharacters(input));**

            if (string.IsNullOrEmpty(input))
            {
                return;
            }

            _selectedTextChangesMadeSinceLastUndoSnapshot++;
            SnapshotUndoRedo(ignoreChangeCount: false);

            var currentText = Text ?? string.Empty;
     
            var selectionLength = Math.Abs(SelectionStart - SelectionEnd);
            var newLength = input.Length + currentText.Length - selectionLength;

            if (MaxLength > 0 && newLength > MaxLength)
            {
                input = input.Remove(Math.Max(0, input.Length - (newLength - MaxLength)));
                newLength = MaxLength;
            }

            if (!string.IsNullOrEmpty(input))
            {
                var textBuilder = StringBuilderCache.Acquire(Math.Max(currentText.Length, newLength));
                textBuilder.Append(currentText);

                var caretIndex = CaretIndex;

                if (selectionLength != 0)
                {
                    var (start, _) = GetSelectionRange();

                    textBuilder.Remove(start, selectionLength);

                    caretIndex = start;
                }

                textBuilder.Insert(caretIndex, input);

                SetCurrentValue(TextProperty, StringBuilderCache.GetStringAndRelease(textBuilder));

                ClearSelection();

                if (IsUndoEnabled)
                {
                    _undoRedoHelper.DiscardRedo();
                }

                SetCurrentValue(CaretIndexProperty, caretIndex + input.Length);
            }
        }

TextBoxCs.txt

cesarchefinho avatar Jun 28 '23 01:06 cesarchefinho