123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896 |
- using System.Data;
- using System.Globalization;
- using Terminal.Gui.Resources;
- namespace Terminal.Gui;
- /// <summary>Single-line text entry <see cref="View"/></summary>
- /// <remarks>The <see cref="TextField"/> <see cref="View"/> provides editing functionality and mouse support.</remarks>
- public class TextField : View
- {
- private readonly HistoryText _historyText;
- private CultureInfo _currentCulture;
- private int _cursorPosition;
- private bool _isButtonPressed;
- private bool _isButtonReleased;
- private bool _isDrawing;
- private int _preTextChangedCursorPos;
- private int _selectedStart; // -1 represents there is no text selection.
- private string _selectedText;
- private int _start;
- private List<Rune> _text;
- /// <summary>
- /// Initializes a new instance of the <see cref="TextField"/> class using <see cref="LayoutStyle.Computed"/>
- /// positioning.
- /// </summary>
- public TextField ()
- {
- _historyText = new HistoryText ();
- _isButtonReleased = true;
- _selectedStart = -1;
- _text = new List<Rune> ();
- CaptionColor = new Color (Color.DarkGray);
- ReadOnly = false;
- Autocomplete = new TextFieldAutocomplete ();
- Height = 1;
- CanFocus = true;
- Used = true;
- WantMousePositionReports = true;
- _historyText.ChangeText += HistoryText_ChangeText;
- Initialized += TextField_Initialized;
- LayoutComplete += TextField_LayoutComplete;
- // Things this view knows how to do
- AddCommand (
- Command.DeleteCharRight,
- () =>
- {
- DeleteCharRight ();
- return true;
- }
- );
- AddCommand (
- Command.DeleteCharLeft,
- () =>
- {
- DeleteCharLeft (false);
- return true;
- }
- );
- AddCommand (
- Command.LeftHomeExtend,
- () =>
- {
- MoveHomeExtend ();
- return true;
- }
- );
- AddCommand (
- Command.RightEndExtend,
- () =>
- {
- MoveEndExtend ();
- return true;
- }
- );
- AddCommand (
- Command.LeftHome,
- () =>
- {
- MoveHome ();
- return true;
- }
- );
- AddCommand (
- Command.LeftExtend,
- () =>
- {
- MoveLeftExtend ();
- return true;
- }
- );
- AddCommand (
- Command.RightExtend,
- () =>
- {
- MoveRightExtend ();
- return true;
- }
- );
- AddCommand (
- Command.WordLeftExtend,
- () =>
- {
- MoveWordLeftExtend ();
- return true;
- }
- );
- AddCommand (
- Command.WordRightExtend,
- () =>
- {
- MoveWordRightExtend ();
- return true;
- }
- );
- AddCommand (
- Command.Left,
- () =>
- {
- MoveLeft ();
- return true;
- }
- );
- AddCommand (
- Command.RightEnd,
- () =>
- {
- MoveEnd ();
- return true;
- }
- );
- AddCommand (
- Command.Right,
- () =>
- {
- MoveRight ();
- return true;
- }
- );
- AddCommand (
- Command.CutToEndLine,
- () =>
- {
- KillToEnd ();
- return true;
- }
- );
- AddCommand (
- Command.CutToStartLine,
- () =>
- {
- KillToStart ();
- return true;
- }
- );
- AddCommand (
- Command.Undo,
- () =>
- {
- Undo ();
- return true;
- }
- );
- AddCommand (
- Command.Redo,
- () =>
- {
- Redo ();
- return true;
- }
- );
- AddCommand (
- Command.WordLeft,
- () =>
- {
- MoveWordLeft ();
- return true;
- }
- );
- AddCommand (
- Command.WordRight,
- () =>
- {
- MoveWordRight ();
- return true;
- }
- );
- AddCommand (
- Command.KillWordForwards,
- () =>
- {
- KillWordForwards ();
- return true;
- }
- );
- AddCommand (
- Command.KillWordBackwards,
- () =>
- {
- KillWordBackwards ();
- return true;
- }
- );
- AddCommand (
- Command.ToggleOverwrite,
- () =>
- {
- SetOverwrite (!Used);
- return true;
- }
- );
- AddCommand (
- Command.EnableOverwrite,
- () =>
- {
- SetOverwrite (true);
- return true;
- }
- );
- AddCommand (
- Command.DisableOverwrite,
- () =>
- {
- SetOverwrite (false);
- return true;
- }
- );
- AddCommand (
- Command.Copy,
- () =>
- {
- Copy ();
- return true;
- }
- );
- AddCommand (
- Command.Cut,
- () =>
- {
- Cut ();
- return true;
- }
- );
- AddCommand (
- Command.Paste,
- () =>
- {
- Paste ();
- return true;
- }
- );
- AddCommand (
- Command.SelectAll,
- () =>
- {
- SelectAll ();
- return true;
- }
- );
- AddCommand (
- Command.DeleteAll,
- () =>
- {
- DeleteAll ();
- return true;
- }
- );
- AddCommand (
- Command.ShowContextMenu,
- () =>
- {
- ShowContextMenu ();
- return true;
- }
- );
- // OnAccept returns true if the event is canceled.
- // By Default pressing ENTER should be ignored (Invoke(Command.Accept) should return false).
- AddCommand (Command.Accept, () => OnAccept () != true);
- // Default keybindings for this view
- // We follow this as closely as possible: https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts
- KeyBindings.Add (Key.Delete, Command.DeleteCharRight);
- KeyBindings.Add (Key.D.WithCtrl, Command.DeleteCharRight);
- KeyBindings.Add (Key.Backspace, Command.DeleteCharLeft);
- KeyBindings.Add (Key.Home.WithShift, Command.LeftHomeExtend);
- KeyBindings.Add (Key.Home.WithShift.WithCtrl, Command.LeftHomeExtend);
- KeyBindings.Add (Key.A.WithShift.WithCtrl, Command.LeftHomeExtend);
- KeyBindings.Add (Key.End.WithShift, Command.RightEndExtend);
- KeyBindings.Add (Key.End.WithShift.WithCtrl, Command.RightEndExtend);
- KeyBindings.Add (Key.E.WithShift.WithCtrl, Command.RightEndExtend);
- KeyBindings.Add (Key.Home, Command.LeftHome);
- KeyBindings.Add (Key.Home.WithCtrl, Command.LeftHome);
- KeyBindings.Add (Key.A.WithCtrl, Command.LeftHome);
- KeyBindings.Add (Key.CursorLeft.WithShift, Command.LeftExtend);
- KeyBindings.Add (Key.CursorUp.WithShift, Command.LeftExtend);
- KeyBindings.Add (Key.CursorRight.WithShift, Command.RightExtend);
- KeyBindings.Add (Key.CursorDown.WithShift, Command.RightExtend);
- KeyBindings.Add (Key.CursorLeft.WithShift.WithCtrl, Command.WordLeftExtend);
- KeyBindings.Add (Key.CursorUp.WithShift.WithCtrl, Command.WordLeftExtend);
- KeyBindings.Add (Key.CursorRight.WithShift.WithCtrl, Command.WordRightExtend);
- KeyBindings.Add (Key.CursorDown.WithShift.WithCtrl, Command.WordRightExtend);
- KeyBindings.Add (Key.CursorLeft, Command.Left);
- KeyBindings.Add (Key.B.WithCtrl, Command.Left);
- KeyBindings.Add (Key.End, Command.RightEnd);
- KeyBindings.Add (Key.End.WithCtrl, Command.RightEnd);
- KeyBindings.Add (Key.E.WithCtrl, Command.RightEnd);
- KeyBindings.Add (Key.CursorRight, Command.Right);
- KeyBindings.Add (Key.F.WithCtrl, Command.Right);
- KeyBindings.Add (Key.K.WithCtrl, Command.CutToEndLine);
- KeyBindings.Add (Key.K.WithCtrl.WithShift, Command.CutToStartLine);
- KeyBindings.Add (Key.Z.WithCtrl, Command.Undo);
- KeyBindings.Add (Key.Y.WithCtrl, Command.Redo);
- KeyBindings.Add (Key.CursorLeft.WithCtrl, Command.WordLeft);
- KeyBindings.Add (Key.CursorUp.WithCtrl, Command.WordLeft);
- KeyBindings.Add (Key.CursorRight.WithCtrl, Command.WordRight);
- KeyBindings.Add (Key.CursorDown.WithCtrl, Command.WordRight);
- #if UNIX_KEY_BINDINGS
- KeyBindings.Add (Key.F.WithShift.WithAlt, Command.WordRightExtend);
- KeyBindings.Add (Key.K.WithAlt, Command.CutToStartLine);
- KeyBindings.Add (Key.B.WithShift.WithAlt, Command.WordLeftExtend);
- KeyBindings.Add (Key.B.WithAlt, Command.WordLeft);
- KeyBindings.Add (Key.F.WithAlt, Command.WordRight);
- KeyBindings.Add (Key.Backspace.WithAlt, Command.Undo);
- #endif
- KeyBindings.Add (Key.Delete.WithCtrl, Command.KillWordForwards);
- KeyBindings.Add (Key.Backspace.WithCtrl, Command.KillWordBackwards);
- KeyBindings.Add (Key.InsertChar, Command.ToggleOverwrite);
- KeyBindings.Add (Key.C.WithCtrl, Command.Copy);
- KeyBindings.Add (Key.X.WithCtrl, Command.Cut);
- KeyBindings.Add (Key.V.WithCtrl, Command.Paste);
- KeyBindings.Add (Key.T.WithCtrl, Command.SelectAll);
- KeyBindings.Add (Key.R.WithCtrl, Command.DeleteAll);
- KeyBindings.Add (Key.D.WithCtrl.WithShift, Command.DeleteAll);
- _currentCulture = Thread.CurrentThread.CurrentUICulture;
- ContextMenu = new ContextMenu { Host = this, MenuItems = BuildContextMenuBarItem () };
- ContextMenu.KeyChanged += ContextMenu_KeyChanged;
- KeyBindings.Add (ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu);
- KeyBindings.Add (Key.Enter, Command.Accept);
- }
- /// <summary>
- /// Provides autocomplete context menu based on suggestions at the current cursor position. Configure
- /// <see cref="ISuggestionGenerator"/> to enable this feature.
- /// </summary>
- public IAutocomplete Autocomplete { get; set; }
- /// <summary>
- /// Gets or sets the text to render in control when no value has been entered yet and the <see cref="View"/> does
- /// not yet have input focus.
- /// </summary>
- public string Caption { get; set; }
- /// <summary>Gets or sets the foreground <see cref="Color"/> to use when rendering <see cref="Caption"/>.</summary>
- public Color CaptionColor { get; set; }
- /// <summary>Get the <see cref="ContextMenu"/> for this view.</summary>
- public ContextMenu ContextMenu { get; }
- /// <summary>Sets or gets the current cursor position.</summary>
- public virtual int CursorPosition
- {
- get => _cursorPosition;
- set
- {
- if (value < 0)
- {
- _cursorPosition = 0;
- }
- else if (value > _text.Count)
- {
- _cursorPosition = _text.Count;
- }
- else
- {
- _cursorPosition = value;
- }
- PrepareSelection (_selectedStart, _cursorPosition - _selectedStart);
- }
- }
- /// <summary>
- /// Indicates whatever the text has history changes or not. <see langword="true"/> if the text has history changes
- /// <see langword="false"/> otherwise.
- /// </summary>
- public bool HasHistoryChanges => _historyText.HasHistoryChanges;
- /// <summary>
- /// Indicates whatever the text was changed or not. <see langword="true"/> if the text was changed
- /// <see langword="false"/> otherwise.
- /// </summary>
- public bool IsDirty => _historyText.IsDirty (Text);
- /// <summary>If set to true its not allow any changes in the text.</summary>
- public bool ReadOnly { get; set; }
- /// <summary>Gets the left offset position.</summary>
- public int ScrollOffset { get; private set; }
- /// <summary>
- /// Sets the secret property.
- /// <remarks>This makes the text entry suitable for entering passwords.</remarks>
- /// </summary>
- public bool Secret { get; set; }
- /// <summary>Length of the selected text.</summary>
- public int SelectedLength { get; private set; }
- /// <summary>Start position of the selected text.</summary>
- public int SelectedStart
- {
- get => _selectedStart;
- set
- {
- if (value < -1)
- {
- _selectedStart = -1;
- }
- else if (value > _text.Count)
- {
- _selectedStart = _text.Count;
- }
- else
- {
- _selectedStart = value;
- }
- PrepareSelection (_selectedStart, _cursorPosition - _selectedStart);
- }
- }
- /// <summary>The selected text.</summary>
- public string SelectedText
- {
- get => Secret ? null : _selectedText;
- private set => _selectedText = value;
- }
- /// <summary>Sets or gets the text held by the view.</summary>
- public new string Text
- {
- get => StringExtensions.ToString (_text);
- set
- {
- var oldText = StringExtensions.ToString (_text);
- if (oldText == value)
- {
- return;
- }
- StateEventArgs<string> newText = OnTextChanging (value.Replace ("\t", "").Split ("\n") [0]);
- if (newText.Cancel)
- {
- if (_cursorPosition > _text.Count)
- {
- _cursorPosition = _text.Count;
- }
- return;
- }
- ClearAllSelection ();
- _text = newText.NewValue.EnumerateRunes ().ToList ();
- if (!Secret && !_historyText.IsFromHistory)
- {
- _historyText.Add (
- new List<List<RuneCell>> { TextModel.ToRuneCellList (oldText) },
- new Point (_cursorPosition, 0)
- );
- _historyText.Add (
- new List<List<RuneCell>> { TextModel.ToRuneCells (_text) },
- new Point (_cursorPosition, 0),
- HistoryText.LineStatus.Replaced
- );
- }
- OnTextChanged (oldText, StringExtensions.ToString (_text));
- ProcessAutocomplete ();
- if (_cursorPosition > _text.Count)
- {
- _cursorPosition = Math.Max (TextModel.DisplaySize (_text, 0).size - 1, 0);
- }
- Adjust ();
- SetNeedsDisplay ();
- }
- }
- /// <summary>
- /// Tracks whether the text field should be considered "used", that is, that the user has moved in the entry, so
- /// new input should be appended at the cursor position, rather than clearing the entry
- /// </summary>
- public bool Used { get; set; }
- /// <summary>Clear the selected text.</summary>
- public void ClearAllSelection ()
- {
- if (_selectedStart == -1 && SelectedLength == 0 && string.IsNullOrEmpty (_selectedText))
- {
- return;
- }
- _selectedStart = -1;
- SelectedLength = 0;
- _selectedText = null;
- _start = 0;
- SelectedLength = 0;
- SetNeedsDisplay ();
- }
- /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItem"/> items updating the original text.</summary>
- public void ClearHistoryChanges () { _historyText.Clear (Text); }
- /// <summary>Copy the selected text to the clipboard.</summary>
- public virtual void Copy ()
- {
- if (Secret || SelectedLength == 0)
- {
- return;
- }
- Clipboard.Contents = SelectedText;
- }
- /// <summary>Cut the selected text to the clipboard.</summary>
- public virtual void Cut ()
- {
- if (ReadOnly || Secret || SelectedLength == 0)
- {
- return;
- }
- Clipboard.Contents = SelectedText;
- List<Rune> newText = DeleteSelectedText ();
- Text = StringExtensions.ToString (newText);
- Adjust ();
- }
- /// <summary>Deletes all text.</summary>
- public void DeleteAll ()
- {
- if (_text.Count == 0)
- {
- return;
- }
- _selectedStart = 0;
- MoveEndExtend ();
- DeleteCharLeft (false);
- SetNeedsDisplay ();
- }
- /// <summary>Deletes the character to the left.</summary>
- /// <param name="usePreTextChangedCursorPos">
- /// If set to <see langword="true">true</see> use the cursor position cached ;
- /// otherwise use <see cref="CursorPosition"/>. use .
- /// </param>
- public virtual void DeleteCharLeft (bool usePreTextChangedCursorPos)
- {
- if (ReadOnly)
- {
- return;
- }
- _historyText.Add (
- new List<List<RuneCell>> { TextModel.ToRuneCells (_text) },
- new Point (_cursorPosition, 0)
- );
- if (SelectedLength == 0)
- {
- if (_cursorPosition == 0)
- {
- return;
- }
- if (!usePreTextChangedCursorPos)
- {
- _preTextChangedCursorPos = _cursorPosition;
- }
- _cursorPosition--;
- if (_preTextChangedCursorPos < _text.Count)
- {
- SetText (
- _text.GetRange (0, _preTextChangedCursorPos - 1)
- .Concat (
- _text.GetRange (
- _preTextChangedCursorPos,
- _text.Count - _preTextChangedCursorPos
- )
- )
- );
- }
- else
- {
- SetText (_text.GetRange (0, _preTextChangedCursorPos - 1));
- }
- Adjust ();
- }
- else
- {
- List<Rune> newText = DeleteSelectedText ();
- Text = StringExtensions.ToString (newText);
- Adjust ();
- }
- }
- /// <summary>Deletes the character to the right.</summary>
- public virtual void DeleteCharRight ()
- {
- if (ReadOnly)
- {
- return;
- }
- _historyText.Add (
- new List<List<RuneCell>> { TextModel.ToRuneCells (_text) },
- new Point (_cursorPosition, 0)
- );
- if (SelectedLength == 0)
- {
- if (_text.Count == 0 || _text.Count == _cursorPosition)
- {
- return;
- }
- SetText (
- _text.GetRange (0, _cursorPosition)
- .Concat (_text.GetRange (_cursorPosition + 1, _text.Count - (_cursorPosition + 1)))
- );
- Adjust ();
- }
- else
- {
- List<Rune> newText = DeleteSelectedText ();
- Text = StringExtensions.ToString (newText);
- Adjust ();
- }
- }
- /// <inheritdoc/>
- public override Attribute GetNormalColor ()
- {
- ColorScheme cs = ColorScheme;
- if (ColorScheme is null)
- {
- cs = new ColorScheme ();
- }
- return Enabled ? cs.Focus : cs.Disabled;
- }
- /// <summary>
- /// Inserts the given <paramref name="toAdd"/> text at the current cursor position exactly as if the user had just
- /// typed it
- /// </summary>
- /// <param name="toAdd">Text to add</param>
- /// <param name="useOldCursorPos">Use the previous cursor position.</param>
- public void InsertText (string toAdd, bool useOldCursorPos = true)
- {
- foreach (char ch in toAdd)
- {
- Key key;
- try
- {
- key = ch;
- }
- catch (Exception)
- {
- throw new ArgumentException (
- $"Cannot insert character '{ch}' because it does not map to a Key"
- );
- }
- InsertText (key, useOldCursorPos);
- }
- }
- /// <summary>Deletes word backwards.</summary>
- public virtual void KillWordBackwards ()
- {
- ClearAllSelection ();
- (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- SetText (
- _text.GetRange (0, newPos.Value.col)
- .Concat (_text.GetRange (_cursorPosition, _text.Count - _cursorPosition))
- );
- _cursorPosition = newPos.Value.col;
- }
- Adjust ();
- }
- /// <summary>Deletes word forwards.</summary>
- public virtual void KillWordForwards ()
- {
- ClearAllSelection ();
- (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- SetText (
- _text.GetRange (0, _cursorPosition)
- .Concat (_text.GetRange (newPos.Value.col, _text.Count - newPos.Value.col))
- );
- }
- Adjust ();
- }
- /// <inheritdoc/>
- protected internal override bool OnMouseEvent (MouseEvent ev)
- {
- if (!ev.Flags.HasFlag (MouseFlags.Button1Pressed)
- && !ev.Flags.HasFlag (MouseFlags.ReportMousePosition)
- && !ev.Flags.HasFlag (MouseFlags.Button1Released)
- && !ev.Flags.HasFlag (MouseFlags.Button1DoubleClicked)
- && !ev.Flags.HasFlag (MouseFlags.Button1TripleClicked)
- && !ev.Flags.HasFlag (ContextMenu.MouseFlags))
- {
- return base.OnMouseEvent (ev);
- }
- if (!CanFocus)
- {
- return true;
- }
- if (!HasFocus && ev.Flags != MouseFlags.ReportMousePosition)
- {
- SetFocus ();
- }
- // Give autocomplete first opportunity to respond to mouse clicks
- if (SelectedLength == 0 && Autocomplete.OnMouseEvent (ev, true))
- {
- return true;
- }
- if (ev.Flags == MouseFlags.Button1Pressed)
- {
- EnsureHasFocus ();
- PositionCursor (ev);
- if (_isButtonReleased)
- {
- ClearAllSelection ();
- }
- _isButtonReleased = true;
- _isButtonPressed = true;
- }
- else if (ev.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) && _isButtonPressed)
- {
- int x = PositionCursor (ev);
- _isButtonReleased = false;
- PrepareSelection (x);
- if (Application.MouseGrabView is null)
- {
- Application.GrabMouse (this);
- }
- }
- else if (ev.Flags == MouseFlags.Button1Released)
- {
- _isButtonReleased = true;
- _isButtonPressed = false;
- Application.UngrabMouse ();
- }
- else if (ev.Flags == MouseFlags.Button1DoubleClicked)
- {
- EnsureHasFocus ();
- int x = PositionCursor (ev);
- int sbw = x;
- if (x == _text.Count
- || (x > 0 && (char)_text [x - 1].Value != ' ')
- || (x > 0 && (char)_text [x].Value == ' '))
- {
- (int col, int row)? newPosBw = GetModel ().WordBackward (x, 0);
- if (newPosBw is null)
- {
- return true;
- }
- sbw = newPosBw.Value.col;
- }
- if (sbw != -1)
- {
- x = sbw;
- PositionCursor (x);
- }
- (int col, int row)? newPosFw = GetModel ().WordForward (x, 0);
- if (newPosFw is null)
- {
- return true;
- }
- ClearAllSelection ();
- if (newPosFw.Value.col != -1 && sbw != -1)
- {
- _cursorPosition = newPosFw.Value.col;
- }
- PrepareSelection (sbw, newPosFw.Value.col - sbw);
- }
- else if (ev.Flags == MouseFlags.Button1TripleClicked)
- {
- EnsureHasFocus ();
- PositionCursor (0);
- ClearAllSelection ();
- PrepareSelection (0, _text.Count);
- }
- else if (ev.Flags == ContextMenu.MouseFlags)
- {
- ShowContextMenu ();
- }
- SetNeedsDisplay ();
- return true;
- void EnsureHasFocus ()
- {
- if (!HasFocus)
- {
- SetFocus ();
- }
- }
- }
- /// <summary>Moves cursor to the end of the typed text.</summary>
- public void MoveEnd ()
- {
- ClearAllSelection ();
- _cursorPosition = _text.Count;
- Adjust ();
- }
- /// <inheritdoc/>
- public override void OnDrawContent (Rectangle viewport)
- {
- _isDrawing = true;
- var selColor = new Attribute (GetFocusColor ().Background, GetFocusColor ().Foreground);
- SetSelectedStartSelectedLength ();
- Driver?.SetAttribute (GetNormalColor ());
- Move (0, 0);
- int p = ScrollOffset;
- var col = 0;
- int width = Frame.Width + OffSetBackground ();
- int tcount = _text.Count;
- Attribute roc = GetReadOnlyColor ();
- for (int idx = p; idx < tcount; idx++)
- {
- Rune rune = _text [idx];
- int cols = rune.GetColumns ();
- if (idx == _cursorPosition && HasFocus && !Used && SelectedLength == 0 && !ReadOnly)
- {
- Driver?.SetAttribute (selColor);
- }
- else if (ReadOnly)
- {
- Driver?.SetAttribute (
- idx >= _start && SelectedLength > 0 && idx < _start + SelectedLength
- ? selColor
- : roc
- );
- }
- else if (!HasFocus && Enabled)
- {
- Driver?.SetAttribute (GetFocusColor ());
- }
- else if (!Enabled)
- {
- Driver?.SetAttribute (roc);
- }
- else
- {
- Driver?.SetAttribute (
- idx >= _start && SelectedLength > 0 && idx < _start + SelectedLength
- ? selColor
- : ColorScheme.Focus
- );
- }
- if (col + cols <= width)
- {
- Driver?.AddRune (Secret ? Glyphs.Dot : rune);
- }
- if (!TextModel.SetCol (ref col, width, cols))
- {
- break;
- }
- if (idx + 1 < tcount && col + _text [idx + 1].GetColumns () > width)
- {
- break;
- }
- }
- Driver.SetAttribute (GetFocusColor ());
- for (int i = col; i < width; i++)
- {
- Driver.AddRune ((Rune)' ');
- }
- PositionCursor ();
- RenderCaption ();
- ProcessAutocomplete ();
- _isDrawing = false;
- }
- ///// <inheritdoc/>
- //public override bool OnEnter (View view)
- //{
- // if (IsInitialized)
- // {
- // Application.Driver.SetCursorVisibility (CursorVisibility.Default);
- // }
- // return base.OnEnter (view);
- //}
- /// <inheritdoc/>
- public override bool? OnInvokingKeyBindings (Key a)
- {
- // Give autocomplete first opportunity to respond to key presses
- if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (a))
- {
- return true;
- }
- return base.OnInvokingKeyBindings (a);
- }
- /// <inheritdoc/>
- public override bool OnLeave (View view)
- {
- if (Application.MouseGrabView is { } && Application.MouseGrabView == this)
- {
- Application.UngrabMouse ();
- }
- //if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
- // ClearAllSelection ();
- return base.OnLeave (view);
- }
- /// TODO: Flush out these docs
- /// <summary>
- /// Processes key presses for the <see cref="TextField"/>.
- /// <remarks>
- /// The <see cref="TextField"/> control responds to the following keys:
- /// <list type="table">
- /// <listheader>
- /// <term>Keys</term> <description>Function</description>
- /// </listheader>
- /// <item>
- /// <term><see cref="Key.Delete"/>, <see cref="Key.Backspace"/></term>
- /// <description>Deletes the character before cursor.</description>
- /// </item>
- /// </list>
- /// </remarks>
- /// </summary>
- /// <param name="a"></param>
- /// <returns></returns>
- public override bool OnProcessKeyDown (Key a)
- {
- // Remember the cursor position because the new calculated cursor position is needed
- // to be set BEFORE the TextChanged event is triggered.
- // Needed for the Elmish Wrapper issue https://github.com/DieselMeister/Terminal.Gui.Elmish/issues/2
- _preTextChangedCursorPos = _cursorPosition;
- // Ignore other control characters.
- if (!a.IsKeyCodeAtoZ && (a.KeyCode < KeyCode.Space || a.KeyCode > KeyCode.CharMask))
- {
- return false;
- }
- if (ReadOnly)
- {
- return true;
- }
- InsertText (a, true);
- return true;
- }
- /// <summary>Virtual method that invoke the <see cref="TextChanging"/> event if it's defined.</summary>
- /// <param name="newText">The new text to be replaced.</param>
- /// <returns>Returns the <see cref="StringEventArgs"/></returns>
- public virtual StateEventArgs<string> OnTextChanging (string newText)
- {
- StateEventArgs<string> ev = new (string.Empty, newText);
- TextChanging?.Invoke (this, ev);
- return ev;
- }
- /// <summary>Paste the selected text from the clipboard.</summary>
- public virtual void Paste ()
- {
- if (ReadOnly || string.IsNullOrEmpty (Clipboard.Contents))
- {
- return;
- }
- SetSelectedStartSelectedLength ();
- int selStart = _start == -1 ? CursorPosition : _start;
- string cbTxt = Clipboard.Contents.Split ("\n") [0] ?? "";
- Text = StringExtensions.ToString (_text.GetRange (0, selStart))
- + cbTxt
- + StringExtensions.ToString (
- _text.GetRange (
- selStart + SelectedLength,
- _text.Count - (selStart + SelectedLength)
- )
- );
- _cursorPosition = Math.Min (selStart + cbTxt.GetRuneCount (), _text.Count);
- ClearAllSelection ();
- SetNeedsDisplay ();
- Adjust ();
- }
- /// <summary>Sets the cursor position.</summary>
- public override Point? PositionCursor ()
- {
- ProcessAutocomplete ();
- var col = 0;
- for (int idx = ScrollOffset < 0 ? 0 : ScrollOffset; idx < _text.Count; idx++)
- {
- if (idx == _cursorPosition)
- {
- break;
- }
- int cols = _text [idx].GetColumns ();
- TextModel.SetCol (ref col, Frame.Width - 1, cols);
- }
- int pos = _cursorPosition - ScrollOffset + Math.Min (Frame.X, 0);
- Move (pos, 0);
- return new Point (pos, 0);
- }
- /// <summary>Redoes the latest changes.</summary>
- public void Redo ()
- {
- if (ReadOnly)
- {
- return;
- }
- _historyText.Redo ();
- }
- /// <summary>Selects all text.</summary>
- public void SelectAll ()
- {
- if (_text.Count == 0)
- {
- return;
- }
- _selectedStart = 0;
- MoveEndExtend ();
- SetNeedsDisplay ();
- }
- ///// <summary>
- ///// Changed event, raised when the text has changed.
- ///// <remarks>
- ///// This event is raised when the <see cref="Text"/> changes. The passed <see cref="EventArgs"/> is a
- ///// <see cref="string"/> containing the old value.
- ///// </remarks>
- ///// </summary>
- //public event EventHandler<StateEventArgs<string>> TextChanged;
- /// <summary>Changing event, raised before the <see cref="Text"/> changes and can be canceled or changing the new text.</summary>
- public event EventHandler<StateEventArgs<string>> TextChanging;
- /// <summary>Undoes the latest changes.</summary>
- public void Undo ()
- {
- if (ReadOnly)
- {
- return;
- }
- _historyText.Undo ();
- }
- /// <summary>
- /// Returns <see langword="true"/> if the current cursor position is at the end of the <see cref="Text"/>. This
- /// includes when it is empty.
- /// </summary>
- /// <returns></returns>
- internal bool CursorIsAtEnd () { return CursorPosition == Text.Length; }
- /// <summary>Returns <see langword="true"/> if the current cursor position is at the start of the <see cref="TextField"/>.</summary>
- /// <returns></returns>
- internal bool CursorIsAtStart () { return CursorPosition <= 0; }
- private void Adjust ()
- {
- if (!IsAdded)
- {
- return;
- }
- int offB = OffSetBackground ();
- bool need = NeedsDisplay || !Used;
- if (_cursorPosition < ScrollOffset)
- {
- ScrollOffset = _cursorPosition;
- need = true;
- }
- else if (Frame.Width > 0
- && (ScrollOffset + _cursorPosition - (Frame.Width + offB) == 0
- || TextModel.DisplaySize (_text, ScrollOffset, _cursorPosition).size >= Frame.Width + offB))
- {
- ScrollOffset = Math.Max (
- TextModel.CalculateLeftColumn (
- _text,
- ScrollOffset,
- _cursorPosition,
- Frame.Width + offB
- ),
- 0
- );
- need = true;
- }
- if (need)
- {
- SetNeedsDisplay ();
- }
- else
- {
- PositionCursor ();
- }
- }
- private MenuBarItem BuildContextMenuBarItem ()
- {
- return new MenuBarItem (
- new MenuItem []
- {
- new (
- Strings.ctxSelectAll,
- "",
- () => SelectAll (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.SelectAll)
- ),
- new (
- Strings.ctxDeleteAll,
- "",
- () => DeleteAll (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.DeleteAll)
- ),
- new (
- Strings.ctxCopy,
- "",
- () => Copy (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.Copy)
- ),
- new (
- Strings.ctxCut,
- "",
- () => Cut (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.Cut)
- ),
- new (
- Strings.ctxPaste,
- "",
- () => Paste (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.Paste)
- ),
- new (
- Strings.ctxUndo,
- "",
- () => Undo (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.Undo)
- ),
- new (
- Strings.ctxRedo,
- "",
- () => Redo (),
- null,
- null,
- (KeyCode)KeyBindings.GetKeyFromCommands (Command.Redo)
- )
- }
- );
- }
- private void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e) { KeyBindings.Replace (e.OldKey.KeyCode, e.NewKey.KeyCode); }
- private List<Rune> DeleteSelectedText ()
- {
- SetSelectedStartSelectedLength ();
- int selStart = SelectedStart > -1 ? _start : _cursorPosition;
- string newText = StringExtensions.ToString (_text.GetRange (0, selStart))
- + StringExtensions.ToString (
- _text.GetRange (
- selStart + SelectedLength,
- _text.Count - (selStart + SelectedLength)
- )
- );
- ClearAllSelection ();
- _cursorPosition = selStart >= newText.GetRuneCount () ? newText.GetRuneCount () : selStart;
- return newText.ToRuneList ();
- }
- private void GenerateSuggestions ()
- {
- List<RuneCell> currentLine = TextModel.ToRuneCellList (Text);
- int cursorPosition = Math.Min (CursorPosition, currentLine.Count);
- Autocomplete.Context = new AutocompleteContext (
- currentLine,
- cursorPosition,
- Autocomplete.Context != null
- ? Autocomplete.Context.Canceled
- : false
- );
- Autocomplete.GenerateSuggestions (
- Autocomplete.Context
- );
- }
- private TextModel GetModel ()
- {
- var model = new TextModel ();
- model.LoadString (Text);
- return model;
- }
- private Attribute GetReadOnlyColor ()
- {
- ColorScheme cs = ColorScheme;
- if (ColorScheme is null)
- {
- cs = new ColorScheme ();
- }
- if (cs.Disabled.Foreground == cs.Focus.Background)
- {
- return new Attribute (cs.Focus.Foreground, cs.Focus.Background);
- }
- return new Attribute (cs.Disabled.Foreground, cs.Focus.Background);
- }
- private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
- {
- if (obj is null)
- {
- return;
- }
- Text = TextModel.ToString (obj?.Lines [obj.CursorPosition.Y]);
- CursorPosition = obj.CursorPosition.X;
- Adjust ();
- }
- private void InsertText (Key a, bool usePreTextChangedCursorPos)
- {
- _historyText.Add (
- new List<List<RuneCell>> { TextModel.ToRuneCells (_text) },
- new Point (_cursorPosition, 0)
- );
- List<Rune> newText = _text;
- if (SelectedLength > 0)
- {
- newText = DeleteSelectedText ();
- _preTextChangedCursorPos = _cursorPosition;
- }
- if (!usePreTextChangedCursorPos)
- {
- _preTextChangedCursorPos = _cursorPosition;
- }
- StringRuneEnumerator kbstr = a.AsRune.ToString ().EnumerateRunes ();
- if (Used)
- {
- _cursorPosition++;
- if (_cursorPosition == newText.Count + 1)
- {
- SetText (newText.Concat (kbstr).ToList ());
- }
- else
- {
- if (_preTextChangedCursorPos > newText.Count)
- {
- _preTextChangedCursorPos = newText.Count;
- }
- SetText (
- newText.GetRange (0, _preTextChangedCursorPos)
- .Concat (kbstr)
- .Concat (
- newText.GetRange (
- _preTextChangedCursorPos,
- Math.Min (
- newText.Count - _preTextChangedCursorPos,
- newText.Count
- )
- )
- )
- );
- }
- }
- else
- {
- SetText (
- newText.GetRange (0, _preTextChangedCursorPos)
- .Concat (kbstr)
- .Concat (
- newText.GetRange (
- Math.Min (_preTextChangedCursorPos + 1, newText.Count),
- Math.Max (newText.Count - _preTextChangedCursorPos - 1, 0)
- )
- )
- );
- _cursorPosition++;
- }
- Adjust ();
- }
- private void KillToEnd ()
- {
- if (ReadOnly)
- {
- return;
- }
- ClearAllSelection ();
- if (_cursorPosition >= _text.Count)
- {
- return;
- }
- SetClipboard (_text.GetRange (_cursorPosition, _text.Count - _cursorPosition));
- SetText (_text.GetRange (0, _cursorPosition));
- Adjust ();
- }
- private void KillToStart ()
- {
- if (ReadOnly)
- {
- return;
- }
- ClearAllSelection ();
- if (_cursorPosition == 0)
- {
- return;
- }
- SetClipboard (_text.GetRange (0, _cursorPosition));
- SetText (_text.GetRange (_cursorPosition, _text.Count - _cursorPosition));
- _cursorPosition = 0;
- Adjust ();
- }
- private void MoveEndExtend ()
- {
- if (_cursorPosition <= _text.Count)
- {
- int x = _cursorPosition;
- _cursorPosition = _text.Count;
- PrepareSelection (x, _cursorPosition - x);
- }
- }
- private void MoveHome ()
- {
- ClearAllSelection ();
- _cursorPosition = 0;
- Adjust ();
- }
- private void MoveHomeExtend ()
- {
- if (_cursorPosition > 0)
- {
- int x = _cursorPosition;
- _cursorPosition = 0;
- PrepareSelection (x, _cursorPosition - x);
- }
- }
- private void MoveLeft ()
- {
- ClearAllSelection ();
- if (_cursorPosition > 0)
- {
- _cursorPosition--;
- Adjust ();
- }
- }
- private void MoveLeftExtend ()
- {
- if (_cursorPosition > 0)
- {
- PrepareSelection (_cursorPosition--, -1);
- }
- }
- private void MoveRight ()
- {
- ClearAllSelection ();
- if (_cursorPosition == _text.Count)
- {
- return;
- }
- _cursorPosition++;
- Adjust ();
- }
- private void MoveRightExtend ()
- {
- if (_cursorPosition < _text.Count)
- {
- PrepareSelection (_cursorPosition++, 1);
- }
- }
- private void MoveWordLeft ()
- {
- ClearAllSelection ();
- (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- _cursorPosition = newPos.Value.col;
- }
- Adjust ();
- }
- private void MoveWordLeftExtend ()
- {
- if (_cursorPosition > 0)
- {
- int x = Math.Min (
- _start > -1 && _start > _cursorPosition ? _start : _cursorPosition,
- _text.Count
- );
- if (x > 0)
- {
- (int col, int row)? newPos = GetModel ().WordBackward (x, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- _cursorPosition = newPos.Value.col;
- }
- PrepareSelection (x, newPos.Value.col - x);
- }
- }
- }
- private void MoveWordRight ()
- {
- ClearAllSelection ();
- (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- _cursorPosition = newPos.Value.col;
- }
- Adjust ();
- }
- private void MoveWordRightExtend ()
- {
- if (_cursorPosition < _text.Count)
- {
- int x = _start > -1 && _start > _cursorPosition ? _start : _cursorPosition;
- (int col, int row)? newPos = GetModel ().WordForward (x, 0);
- if (newPos is null)
- {
- return;
- }
- if (newPos.Value.col != -1)
- {
- _cursorPosition = newPos.Value.col;
- }
- PrepareSelection (x, newPos.Value.col - x);
- }
- }
- // BUGBUG: This assumes Frame == Viewport. It's also not clear what the intention is. For now, changed to always return 0.
- private int OffSetBackground ()
- {
- var offB = 0;
- if (SuperView?.Frame.Right - Frame.Right < 0)
- {
- offB = SuperView.Frame.Right - Frame.Right - 1;
- }
- return 0;//offB;
- }
- private int PositionCursor (MouseEvent ev)
- {
- return PositionCursor (TextModel.GetColFromX (_text, ScrollOffset, ev.X), false);
- }
- private int PositionCursor (int x, bool getX = true)
- {
- int pX = x;
- if (getX)
- {
- pX = TextModel.GetColFromX (_text, ScrollOffset, x);
- }
- if (ScrollOffset + pX > _text.Count)
- {
- _cursorPosition = _text.Count;
- }
- else if (ScrollOffset + pX < ScrollOffset)
- {
- _cursorPosition = 0;
- }
- else
- {
- _cursorPosition = ScrollOffset + pX;
- }
- return _cursorPosition;
- }
- private void PrepareSelection (int x, int direction = 0)
- {
- x = x + ScrollOffset < -1 ? 0 : x;
- _selectedStart = _selectedStart == -1 && _text.Count > 0 && x >= 0 && x <= _text.Count
- ? x
- : _selectedStart;
- if (_selectedStart > -1)
- {
- SelectedLength = Math.Abs (
- x + direction <= _text.Count
- ? x + direction - _selectedStart
- : _text.Count - _selectedStart
- );
- SetSelectedStartSelectedLength ();
- if (_start > -1 && SelectedLength > 0)
- {
- _selectedText = SelectedLength > 0
- ? StringExtensions.ToString (
- _text.GetRange (
- _start < 0 ? 0 : _start,
- SelectedLength > _text.Count
- ? _text.Count
- : SelectedLength
- )
- )
- : "";
- if (ScrollOffset > _start)
- {
- ScrollOffset = _start;
- }
- }
- else if (_start > -1 && SelectedLength == 0)
- {
- _selectedText = null;
- }
- SetNeedsDisplay ();
- }
- else if (SelectedLength > 0 || _selectedText is { })
- {
- ClearAllSelection ();
- }
- Adjust ();
- }
- private void ProcessAutocomplete ()
- {
- if (_isDrawing)
- {
- return;
- }
- if (SelectedLength > 0)
- {
- return;
- }
- // draw autocomplete
- GenerateSuggestions ();
- var renderAt = new Point (
- Autocomplete.Context.CursorPosition,
- 0
- );
- Autocomplete.RenderOverlay (renderAt);
- }
- private void RenderCaption ()
- {
- if (HasFocus
- || Caption == null
- || Caption.Length == 0
- || Text?.Length > 0)
- {
- return;
- }
- var color = new Attribute (CaptionColor, GetNormalColor ().Background);
- Driver.SetAttribute (color);
- Move (0, 0);
- string render = Caption;
- if (render.GetColumns () > Viewport.Width)
- {
- render = render [..Viewport.Width];
- }
- Driver.AddStr (render);
- }
- private void SetClipboard (IEnumerable<Rune> text)
- {
- if (!Secret)
- {
- Clipboard.Contents = StringExtensions.ToString (text.ToList ());
- }
- }
- private void SetOverwrite (bool overwrite)
- {
- Used = overwrite;
- SetNeedsDisplay ();
- }
- private void SetSelectedStartSelectedLength ()
- {
- if (SelectedStart > -1 && _cursorPosition < SelectedStart)
- {
- _start = _cursorPosition;
- }
- else
- {
- _start = SelectedStart;
- }
- }
- private void SetText (List<Rune> newText) { Text = StringExtensions.ToString (newText); }
- private void SetText (IEnumerable<Rune> newText) { SetText (newText.ToList ()); }
- private void ShowContextMenu ()
- {
- if (_currentCulture != Thread.CurrentThread.CurrentUICulture)
- {
- _currentCulture = Thread.CurrentThread.CurrentUICulture;
- ContextMenu.MenuItems = BuildContextMenuBarItem ();
- }
- ContextMenu.Show ();
- }
- private void TextField_Initialized (object sender, EventArgs e)
- {
- _cursorPosition = Text.GetRuneCount ();
- if (Viewport.Width > 0)
- {
- ScrollOffset = _cursorPosition > Viewport.Width + 1 ? _cursorPosition - Viewport.Width + 1 : 0;
- }
- Autocomplete.HostControl = this;
- Autocomplete.PopupInsideContainer = false;
- }
- private void TextField_LayoutComplete (object sender, LayoutEventArgs e)
- {
- // Don't let height > 1
- if (Frame.Height > 1)
- {
- Height = 1;
- }
- }
- }
- /// <summary>
- /// Renders an overlay on another view at a given point that allows selecting from a range of 'autocomplete'
- /// options. An implementation on a TextField.
- /// </summary>
- public class TextFieldAutocomplete : PopupAutocomplete
- {
- /// <inheritdoc/>
- protected override void DeleteTextBackwards () { ((TextField)HostControl).DeleteCharLeft (false); }
- /// <inheritdoc/>
- protected override void InsertText (string accepted) { ((TextField)HostControl).InsertText (accepted, false); }
- /// <inheritdoc/>
- protected override void SetCursorPosition (int column) { ((TextField)HostControl).CursorPosition = column; }
- }
|