using System; using System.Linq; namespace FooEditEngine { /// /// イベントパラメーター /// public sealed class ShowingCompleteBoxEventArgs : EventArgs { /// /// 入力された文字 /// public string KeyChar; /// /// 入力した単語と一致したコレクションのインデックス。一致しないなら-1をセットする /// public int foundIndex; /// /// 入力しようとした単語を設定する /// public string inputedWord; /// /// 補完対象のテキストボックス /// public Document textbox; /// /// キャレット座標 /// public Point CaretPostion; /// /// コンストラクター /// /// /// /// public ShowingCompleteBoxEventArgs(string keyChar, Document textbox, Point caret_pos) { this.inputedWord = null; this.KeyChar = keyChar; this.foundIndex = -1; this.textbox = textbox; this.CaretPostion = caret_pos; } } /// /// イベントパラメーター /// public sealed class SelectItemEventArgs : EventArgs { /// /// 入力中の単語 /// public string inputing_word; /// /// 補完対象のテキストボックス /// public Document textbox; /// /// 補完候補 /// public ICompleteItem item; /// /// コンストラクター /// /// /// /// public SelectItemEventArgs(ICompleteItem item, string inputing_word, Document textbox) { this.item = item; this.inputing_word = inputing_word; this.textbox = textbox; } } /// /// イベントパラメーターイベントパラメーター /// public sealed class CollectCompleteItemEventArgs : EventArgs { /// /// 入力された行 /// public int InputedRow; /// /// 補完対象のテキストボックス /// public Document textbox; /// /// コンストラクター /// /// public CollectCompleteItemEventArgs(Document textbox) { this.textbox = textbox; this.InputedRow = textbox.CaretPostion.row - 1; if (this.InputedRow < 0) this.InputedRow = 0; } } /// /// イベントパンドラーの定義 /// /// /// public delegate void SelectItemEventHandler(object sender,SelectItemEventArgs e); /// /// イベントパンドラーの定義 /// /// /// public delegate void ShowingCompleteBoxEnventHandler(object sender, ShowingCompleteBoxEventArgs e); /// /// 自動補完のベースクラス /// public class AutoCompleteBoxBase { const int InputLength = 2; //補完を開始する文字の長さ /// /// 対象となるドキュメント /// protected Document Document { get; private set; } /// /// コンストラクター /// /// 対象となるDocumentWindow public AutoCompleteBoxBase(Document document) { this.SelectItem = (s, e) => { string inputing_word = e.inputing_word; string word = e.item.word; var doc = e.textbox; //キャレットは入力された文字の後ろにあるので、一致する分だけ選択して置き換える int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion); int start = caretIndex - inputing_word.Length; if (start < 0) start = 0; doc.Replace(start, inputing_word.Length, word); doc.RequestRedraw(); }; this.ShowingCompleteBox = (s, e) => { AutoCompleteBoxBase box = (AutoCompleteBoxBase)s; var doc = e.textbox; int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion); int inputingIndex = caretIndex - 1; if (inputingIndex < 0) inputingIndex = 0; e.inputedWord = CompleteHelper.GetWord(doc, inputingIndex, box.Operators) + e.KeyChar; if (e.inputedWord == null) return; for (int i = 0; i < box.Items.Count; i++) { CompleteWord item = (CompleteWord)box.Items[i]; if (item.word.StartsWith(e.inputedWord)) { e.foundIndex = i; break; } } }; this.CollectItems = (s, e) => { AutoCompleteBoxBase box = (AutoCompleteBoxBase)s; CompleteHelper.AddCompleteWords(box.Items, box.Operators, e.textbox.LayoutLines[e.InputedRow]); }; this.Operators = new char[] { ' ', '\t', Document.NewLine }; this.Document = document; } internal void ParseInput(string input_text) { if (this.Operators == null || this.ShowingCompleteBox == null || (this.IsCloseCompleteBox == false && input_text == "\b")) return; if (input_text == "\r" || input_text == "\n") { this.CollectItems(this, new CollectCompleteItemEventArgs(this.Document)); return; } this.OpenCompleteBox(input_text); } /// /// 補完候補を追加可能な時に発生するイベント /// public EventHandler CollectItems; /// /// 補完すべき単語が選択されたときに発生するイベント /// public SelectItemEventHandler SelectItem; /// /// UI表示前のイベント /// public ShowingCompleteBoxEnventHandler ShowingCompleteBox; /// /// 区切り文字のリスト /// public char[] Operators { get; set; } /// /// オートコンプリートの対象となる単語のリスト /// public virtual CompleteCollection Items { get; set; } internal Func GetPostion; /// /// 自動補完リストが表示されているかどうか /// protected virtual bool IsCloseCompleteBox { get; } /// /// 自動補完を行うかどうか。行うなら真 /// public bool Enabled { get; set; } /// /// 補完候補の表示要求を処理する /// /// protected virtual void RequestShowCompleteBox(ShowingCompleteBoxEventArgs ev) { } /// /// 補完候補の非表示要求を処理する /// protected virtual void RequestCloseCompleteBox() { } /// /// 補完候補を表示する /// /// 入力しようとしていた文字列 /// 補完候補がなくても表示するなら真。そうでないなら偽 public void OpenCompleteBox(string key_char, bool force = false) { if (!this.Enabled) return; if (this.GetPostion == null) throw new InvalidOperationException("GetPostionがnullです"); Point p = this.GetPostion(this.Document.CaretPostion,this.Document); ShowingCompleteBoxEventArgs ev = new ShowingCompleteBoxEventArgs(key_char, this.Document, p); ShowingCompleteBox(this, ev); bool hasCompleteItem = ev.foundIndex != -1 && ev.inputedWord != null && ev.inputedWord != string.Empty && ev.inputedWord.Length >= InputLength; System.Diagnostics.Debug.WriteLine("hasCompleteItem:{0}", hasCompleteItem); if (force || hasCompleteItem) { RequestShowCompleteBox(ev); } else { RequestCloseCompleteBox(); } } } }