using System.Runtime.InteropServices; namespace Hawkeye.VisionBuilder.Features.ToolEditor { public class CodeCompletionControl : ListBox { private TextBox textBox; private readonly Form _form; [DllImport("user32.dll")] static extern bool GetCaretPos(out Point lpPoint); public CodeCompletionControl(TextBox textBox) { this.textBox = textBox; this.Visible = false; this.Location = new Point(0, 0); this.Width = 200; _form = new Form(); _form.Width = this.Width; _form.Height = 200; _form.Controls.Add(this); this.Dock = DockStyle.Fill; _form.FormBorderStyle = FormBorderStyle.None; _form.ShowInTaskbar = false; _form.TopMost = true; _form.StartPosition = FormStartPosition.Manual; textBox.TextChanged += TextBox_TextChanged; textBox.KeyDown += TextBox_KeyDown; this.KeyDown += CodeCompletionControl_KeyDown; } private void CodeCompletionControl_KeyDown(object? sender, KeyEventArgs e) { if (e.KeyCode == Keys.Up) { if (this.SelectedIndex == 0) { textBox.Focus(); } } else if (e.KeyCode == Keys.Enter && this.Visible && this.SelectedIndex != -1) { Accept(); }else if (e.KeyCode == Keys.Escape) { this.Visible = false; _form.Hide(); } } private void Cancel() { this.Visible = false; _form.Hide(); } private void Accept() { var start = textBox.Text.LastIndexOf("."); if (start == -1) { textBox.Text = this.SelectedItem.ToString(); textBox.SelectionStart = textBox.Text.Length; this.Visible = false; _form.Hide(); return; } textBox.Text = textBox.Text.Substring(0,start+1); textBox.Text += this.SelectedItem.ToString(); textBox.SelectionStart = textBox.Text.Length; this.Visible = false; _form.Hide(); } private void TextBox_TextChanged(object sender, EventArgs e) { if(int.TryParse(textBox.Text,out _))return; if (GetCaretPos(out Point point)) { // Convert screen position to client position // Set location of this control _form.Location = textBox.PointToScreen(new Point(point.X, point.Y + textBox.Size.Height)); ; // Add offset to avoid overlap with text cursor } // Update suggestions var suggestions = GetSuggestions(textBox.Text); this.Items.Clear(); this.Items.AddRange(suggestions.ToArray()); if (this.Items.Count > 0) { _form.Show(); textBox.Focus(); } else { _form.Hide(); } this.Visible = this.Items.Count > 0; } private void TextBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Down && this.Visible) { this.Focus(); this.SelectedIndex = 0; } else if (e.KeyCode == Keys.Escape) { Cancel(); } else if (e.KeyCode == Keys.Enter && this.Visible && this.SelectedIndex != -1) { Accept(); } } public delegate void NeedSugestionsDelegate(string input, List suggestions); public event NeedSugestionsDelegate NeedSugestions =delegate{ }; private List GetSuggestions(string input) { var source = new List(); NeedSugestions(input, source); if (source.Count == 0) { Visible = false; _form.Hide(); } return source.ToList(); } } }