diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs index 71df804..deb9380 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs @@ -12,7 +12,7 @@ using System.Windows.Forms; namespace Acacia.Controls { - public abstract class KAbstractComboBox : ContainerControl, IMessageFilter + public abstract class KAbstractComboBox : ContainerControl { #region Properties @@ -63,11 +63,7 @@ namespace Acacia.Controls _state.AddControl(_edit); _edit.TextChanged += _edit_TextChanged; _edit.LostFocus += _edit_LostFocus; - } - - private void _edit_LostFocus(object sender, EventArgs e) - { - DroppedDown = false; + _edit.PreviewKeyDown += _edit_PreviewKeyDown; } @@ -75,15 +71,15 @@ namespace Acacia.Controls #region Text edit - private void _edit_TextChanged(object sender, EventArgs e) - { - OnTextChanged(new EventArgs()); - } - override public string Text { get { return _edit.Text; } - set { _edit.Text = value; } + set + { + _edit.Text = value; + // Set the cursor after the text + _edit.Select(_edit.Text.Length, 0); + } } public void FocusEdit() @@ -91,6 +87,63 @@ namespace Acacia.Controls _edit.Select(); } + private void _edit_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Escape: + // Escape closes the dropdown + if (DroppedDown) + { + DroppedDown = false; + e.IsInputKey = false; + return; + } + break; + case Keys.Down: + // Down opens the drop down + if (!DroppedDown) + { + DroppedDown = true; + e.IsInputKey = false; + return; + } + break; + } + OnPreviewKeyDown(e); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr GetFocus(); + + private Control GetFocusedControl() + { + Control focusedControl = null; + // To get hold of the focused control: + IntPtr focusedHandle = GetFocus(); + if (focusedHandle != IntPtr.Zero) + // Note that if the focused Control is not a .Net control, then this will return null. + focusedControl = Control.FromHandle(focusedHandle); + return focusedControl; + } + + private void _edit_LostFocus(object sender, EventArgs e) + { + System.Diagnostics.Trace.WriteLine("_edit_LostFocus: " + GetFocusedControl()?.Name); + DroppedDown = false; + } + + protected override void OnGotFocus(EventArgs e) + { + base.OnGotFocus(e); + System.Diagnostics.Trace.WriteLine("OnGotFocus"); + } + + private void _edit_TextChanged(object sender, EventArgs e) + { + OnTextChanged(new EventArgs()); + } + #endregion #region Drop down @@ -118,6 +171,7 @@ namespace Acacia.Controls _dropListHost.Padding = new Padding(0); _dropListHost.Margin = new Padding(0); _dropListHost.AutoSize = false; + _dropListHost.GotFocus += (s, e) => System.Diagnostics.Trace.WriteLine("_dropListHost.GotFocus"); _dropDown = new ToolStripDropDown(); _dropDown.Padding = new Padding(0); @@ -127,89 +181,7 @@ namespace Acacia.Controls _dropDown.Items.Add(_dropListHost); _dropDown.Closed += _dropDown_Closed; _dropDown.AutoClose = false; - - Application.AddMessageFilter(this); - } - - protected override void OnHandleDestroyed(EventArgs e) - { - Application.RemoveMessageFilter(this); - base.OnHandleDestroyed(e); - } - - public bool PreFilterMessage(ref Message m) - { - switch ((WM)m.Msg) - { - case WM.KEYDOWN: - switch((VirtualKeys)m.WParam.ToInt32()) - { - case VirtualKeys.Escape: - // Escape closes the popup - if (DroppedDown) - { - DroppedDown = false; - return true; - } - break; - case VirtualKeys.Down: - // Down opens the drop down - if (!DroppedDown) - { - DroppedDown = true; - return true; - } - break; - } - ForwardKeyMessage(m); - break; - case WM.CHAR: - case WM.KEYUP: - ForwardKeyMessage(m); - break; - case WM.LBUTTONDOWN: - case WM.RBUTTONDOWN: - case WM.MBUTTONDOWN: - case WM.NCLBUTTONDOWN: - case WM.NCRBUTTONDOWN: - case WM.NCMBUTTONDOWN: - if (_dropDown.Visible) - { - // - // When a mouse button is pressed, we should determine if it is within the client coordinates - // of the active dropdown. If not, we should dismiss it. - // - int i = unchecked((int)(long)m.LParam); - short x = (short)(i & 0xFFFF); - short y = (short)((i >> 16) & 0xffff); - Point pt = new Point(x, y); - - // Map to global coordinates - User32.MapWindowPoints(m.HWnd, IntPtr.Zero, ref pt, 1); - System.Diagnostics.Trace.WriteLine(string.Format("MOUSE: {0} - {1}", pt, _dropDown.Bounds)); - if (!_dropDown.Bounds.Contains(pt)) - { - // the user has clicked outside the dropdown - User32.MapWindowPoints(m.HWnd, Handle, ref pt, 1); - if (!ClientRectangle.Contains(pt)) - { - // the user has clicked outside the combo - DroppedDown = false; - } - } - } - break; - } - return false; - } - - private void ForwardKeyMessage(Message m) - { - System.Diagnostics.Trace.WriteLine("KEY: " + m); - if ((WM)m.Msg == WM.KEYDOWN) - { - OnPreviewKeyDown(new PreviewKeyDownEventArgs((Keys)m.WParam.ToInt32())); - } + _dropDown.GotFocus += (s, e) => System.Diagnostics.Trace.WriteLine("_dropDown.GotFocus"); } // Cannot use visibility of _dropDown to keep the open state, as clicking on the button already @@ -249,10 +221,12 @@ namespace Acacia.Controls _dropControl.Height = Util.Bound(prefSize.Height, minHeight, maxHeight); // Show the drop down below the current control _dropDown.Show(this.PointToScreen(new Point(0, Height))); + _dropControl.Capture = true; } else { _dropDown.Close(); + _dropControl.Capture = false; } _isDroppedDown = value; } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs index ac0b30d..bc950ca 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs @@ -47,14 +47,25 @@ namespace Acacia.Controls MaxDropDownItems = 8; _list = new KListBox(); _list.IntegralHeight = true; + _list.TabStop = false; DropControl = _list; _list.DisplayMember = "DisplayName"; // TODO: remove from here _list.SelectedIndexChanged += _list_SelectedIndexChanged; + _list.GotFocus += _list_GotFocus; + } + + private void _list_GotFocus(object sender, EventArgs e) + { + System.Diagnostics.Trace.WriteLine("_list_GotFocus"); + } private void _list_SelectedIndexChanged(object sender, EventArgs e) { - System.Diagnostics.Trace.WriteLine("SELECTED: " + _list.SelectedIndex); + if (_list.SelectedIndex >= 0) + { + Text = _list.SelectedItem.ToString(); + } } public void BeginUpdate() @@ -95,9 +106,11 @@ namespace Acacia.Controls { switch(e.KeyCode) { + // Forward cursor keys to the list case Keys.Down: case Keys.Up: User32.SendMessage(_list.Handle, (int)WM.KEYDOWN, new IntPtr((int)e.KeyCode), IntPtr.Zero); + e.IsInputKey = false; break; default: base.OnPreviewKeyDown(e); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs index b22b389..9738892 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs @@ -16,18 +16,20 @@ namespace Acacia.Controls { SetStyle(ControlStyles.OptimizedDoubleBuffer, true); DrawMode = DrawMode.OwnerDrawFixed; + SetStyle(ControlStyles.Selectable, true); } protected override void OnMouseMove(MouseEventArgs e) { - Point point = PointToClient(Cursor.Position); - int newIndex = IndexFromPoint(point); + int newIndex = IndexFromPoint(PointToClient(Cursor.Position)); if (newIndex != _hoverIndex) { int oldIndex = _hoverIndex; _hoverIndex = newIndex; InvalidateItem(oldIndex); InvalidateItem(_hoverIndex); + if (SelectedIndex != oldIndex && SelectedIndex != _hoverIndex) + InvalidateItem(SelectedIndex); } } @@ -37,6 +39,14 @@ namespace Acacia.Controls _hoverIndex = -1; } + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + // Perform the select here. + // TODO: this really is for ComboBox, where the list hides before the event is handled + SelectedIndex = IndexFromPoint(PointToClient(Cursor.Position)); + } + protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e);