aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Console/ConsoleTextBox.cs
blob: f6fa40b13153babb232c2db473c67c0e2963e943 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
generated by cgit v1.3.1 (git 2.54.0) at 2026-07-23 19:25:51 +0000
 


27'>227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Tango.Console
{
    public class ConsoleTextBox : TextBox
    {
        private Border _caret;
        private ListBox _listSuggestions;
        private Popup _popup;
        private Popup _suggestionsPopup;

        static ConsoleTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ConsoleTextBox), new FrameworkPropertyMetadata(typeof(ConsoleTextBox)));
        }

        public Brush CaretBottomBrush
        {
            get { return (Brush)GetValue(CaretBottomBrushProperty); }
            set { SetValue(CaretBottomBrushProperty, value); }
        }
        public static readonly DependencyProperty CaretBottomBrushProperty =
            DependencyProperty.Register("CaretBottomBrush", typeof(Brush), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public double CaretPosition
        {
            get { return (double)GetValue(CaretPositionProperty); }
            set { SetValue(CaretPositionProperty, value); }
        }
        public static readonly DependencyProperty CaretPositionProperty =
            DependencyProperty.Register("CaretPosition", typeof(double), typeof(ConsoleTextBox), new PropertyMetadata(0.0));

        public bool IsSuggestionsOpened
        {
            get { return (bool)GetValue(IsSuggestionsOpenedProperty); }
            set { SetValue(IsSuggestionsOpenedProperty, value); }
        }
        public static readonly DependencyProperty IsSuggestionsOpenedProperty =
            DependencyProperty.Register("IsSuggestionsOpened", typeof(bool), typeof(ConsoleTextBox), new PropertyMetadata(false));

        public List<ConsoleSuggestion> FilteredSuggestions
        {
            get { return (List<ConsoleSuggestion>)GetValue(FilteredSuggestionsProperty); }
            set { SetValue(FilteredSuggestionsProperty, value); }
        }
        public static readonly DependencyProperty FilteredSuggestionsProperty =
            DependencyProperty.Register("FilteredSuggestions", typeof(List<ConsoleSuggestion>), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public IEnumerable<ConsoleSuggestion> Suggestions
        {
            get { return (IEnumerable<ConsoleSuggestion>)GetValue(SuggestionsProperty); }
            set { SetValue(SuggestionsProperty, value); }
        }
        public static readonly DependencyProperty SuggestionsProperty =
            DependencyProperty.Register("Suggestions", typeof(IEnumerable<ConsoleSuggestion>), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public ConsoleSuggestion SelectedSuggestion
        {
            get { return (ConsoleSuggestion)GetValue(SelectedSuggestionProperty); }
            set { SetValue(SelectedSuggestionProperty, value); }
        }
        public static readonly DependencyProperty SelectedSuggestionProperty =
            DependencyProperty.Register("SelectedSuggestion", typeof(ConsoleSuggestion), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public int MaxSuggestions
        {
            get { return (int)GetValue(MaxSuggestionsProperty); }
            set { SetValue(MaxSuggestionsProperty, value); }
        }
        public static readonly DependencyProperty MaxSuggestionsProperty =
            DependencyProperty.Register("MaxSuggestions", typeof(int), typeof(ConsoleTextBox), new PropertyMetadata(1000));

        public Brush SuggestionsBorderBrush
        {
            get { return (Brush)GetValue(SuggestionsBorderBrushProperty); }
            set { SetValue(SuggestionsBorderBrushProperty, value); }
        }
        public static readonly DependencyProperty SuggestionsBorderBrushProperty =
            DependencyProperty.Register("SuggestionsBorderBrush", typeof(Brush), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public Brush SuggestionsBackground
        {
            get { return (Brush)GetValue(SuggestionsBackgroundProperty); }
            set { SetValue(SuggestionsBackgroundProperty, value); }
        }
        public static readonly DependencyProperty SuggestionsBackgroundProperty =
            DependencyProperty.Register("SuggestionsBackground", typeof(Brush), typeof(ConsoleTextBox), new PropertyMetadata(null));

        public Brush SuggestionsForeground
        {
            get { return (Brush)GetValue(SuggestionsForegroundProperty); }
            set { SetValue(SuggestionsForegroundProperty, value); }
        }
        public static readonly DependencyProperty SuggestionsForegroundProperty =
            DependencyProperty.Register("SuggestionsForeground", typeof(Brush), typeof(ConsoleTextBox), new PropertyMetadata(null));


        public ConsoleTextBox()
        {
            SelectionChanged += (sender, e) => MoveCustomCaret();
            LostFocus += (sender, e) => _caret.Visibility = Visibility.Collapsed;
            GotKeyboardFocus += (sender, e) => _caret.Visibility = Visibility.Visible;
            LostKeyboardFocus += (sender, e) => _caret.Visibility = Visibility.Collapsed;

            Suggestions = ConsoleDictionary.GetKnownCommands().Select(x => new ConsoleSuggestion()
            {
                Name = x.Name,
                Description = x.Description
            }).ToObservableCollection();
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            if (IsSuggestionsOpened)
            {
                if (e.Key == Key.Down)
                {
                    if (_listSuggestions.SelectedIndex < _listSuggestions.Items.Count - 1)
                    {
                        _listSuggestions.SelectedIndex++;
                        _listSuggestions.ScrollIntoView(SelectedSuggestion);

                        _popup.IsOpen = false;

                        if (SelectedSuggestion != null && SelectedSuggestion.Description != null)
                        {
                            _popup.IsOpen = FilteredSuggestions.Count > 0;
                        }
                    }

                    e.Handled = true;
                    return;
                }
                else if (e.Key == Key.Up)
                {
                    if (_listSuggestions.SelectedIndex > 0)
                    {
                        _listSuggestions.SelectedIndex--;
                        _listSuggestions.ScrollIntoView(SelectedSuggestion);

                        _popup.IsOpen = false;
                        if (SelectedSuggestion != null && SelectedSuggestion.Description != null)
                        {
                            _popup.IsOpen = FilteredSuggestions.Count > 0;
                        }
                    }

                    e.Handled = true;
                    return;
                }
                else if (e.Key == Key.Enter)
                {
                    var selectedItem = (_listSuggestions.SelectedItem as ConsoleSuggestion);
                    if (selectedItem != null)
                    {
                        var words = Text.Split(' ').ToList();

                        if (words.Count > 1)
                        {
                            words = words.Take(words.Count - 1).ToList();
                            Text = String.Join(" ", words) + " " + selectedItem.Name;
                        }
                        else
                        {
                            Text = selectedItem.Name;
                        }

                        IsSuggestionsOpened = false;
                        CaretIndex = Text.Length;
                        e.Handled = true;
                        return;
                    }

                    IsSuggestionsOpened = false;
                }
            }

            base.OnPreviewKeyDown(e);
        }

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);

            try
            {
                if (CaretIndex == Text.Length)
                {
                    String lastWord = Text.Split(' ').LastOrDefault();
                    lastWord?.Trim();

                    if (Suggestions != null)
                    {
                        FilteredSuggestions = Suggestions.Where(x => (lastWord.IsNotNullOrEmpty() && x.Name.ToLower().StartsWith(lastWord.ToLower())) || Text.EndsWith(" ")).OrderBy(x => x.Name).Take(MaxSuggestions).ToList();

                        if (Text.Contains(" "))
                        {
                            FilteredSuggestions = FilteredSuggestions.Where(x => x.Type != ConsoleSuggestionType.Command).ToList();
                        }

                        IsSuggestionsOpened = FilteredSuggestions.Count > 0;
                        _popup.IsOpen = false;
                        _popup.IsOpen = FilteredSuggestions.Count > 0 && SelectedSuggestion != null;
                    }
                }
                else
                {
                    IsSuggestionsOpened = false;
                    _popup.IsOpen = false;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                Debugger.Break();
            }
        }

        protected override void OnSelectionChanged(RoutedEventArgs e)
        {
            base.OnSelectionChanged(e);

            if (CaretIndex < Text.Length)
            {
                IsSuggestionsOpened = false;
                _popup.IsOpen = false;
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _caret = GetTemplateChild("PART_Caret") as Border;
            _listSuggestions = GetTemplateChild("PART_listSuggestions") as ListBox;
            _popup = GetTemplateChild("PART_popup") as Popup;
            _suggestionsPopup = GetTemplateChild("PART_SuggestionsPopup") as Popup;
        }

        private void MoveCustomCaret()
        {
            var caretLocation = GetRectFromCharacterIndex(CaretIndex).Location;

            if (!double.IsInfinity(caretLocation.X))
            {
                Canvas.SetLeft(_caret, caretLocation.X);
                CaretPosition = caretLocation.X;

                _suggestionsPopup.PlacementRectangle = new Rect(CaretPosition + 10, 20, 0, 0);
            }
        }
    }
}