1
0
mirror of https://github.com/Kopano-dev/kopano-ol-extension.git synced 2023-10-10 13:37:40 +02:00

Fixed keyboard handling in combo box

This commit is contained in:
Patrick Simpson 2017-06-29 13:37:55 +02:00
parent fdf8350afb
commit acfc47f018

View File

@ -16,87 +16,49 @@ namespace Acacia.Controls
{ {
#region Drop-down list #region Drop-down list
/// <summary>
/// Custom list for the drop-down. Performs a few functions:
/// - Prevents grabbing the focus away from the edit when clicked
/// - Adds hover highlighting
/// - Only commits selection when clicked or externally (through enter in the edit).
/// This prevents updating the text and associated filters when scrolling through the combo.
/// </summary>
private class DropList : ListBox private class DropList : ListBox
{ {
private readonly KComboBox _owner; private readonly KComboBox _owner;
private int _highlightIndex = -1; private int _committedIndex = -1;
public DropList(KComboBox owner) public DropList(KComboBox owner)
{ {
this._owner = owner; this._owner = owner;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
DrawMode = DrawMode.OwnerDrawFixed;
SetStyle(ControlStyles.Selectable, false); SetStyle(ControlStyles.Selectable, false);
BorderStyle = BorderStyle.None; BorderStyle = BorderStyle.None;
} }
protected override void OnMouseMove(MouseEventArgs e) protected override void OnMouseMove(MouseEventArgs e)
{ {
// Use the mouse to highlight the current item // Perform the select to highlight
int newIndex = IndexFromPoint(PointToClient(Cursor.Position)); SelectedIndex = IndexFromPoint(PointToClient(Cursor.Position));
if (newIndex != _highlightIndex)
{
int oldIndex = _highlightIndex;
_highlightIndex = newIndex;
// Invalidate the affected items, which may include a previously selected one
InvalidateItem(oldIndex);
InvalidateItem(_highlightIndex);
if (SelectedIndex != oldIndex && SelectedIndex != _highlightIndex)
InvalidateItem(SelectedIndex);
}
} }
protected override void OnMouseLeave(EventArgs e) protected override void OnMouseLeave(EventArgs e)
{ {
base.OnMouseLeave(e); base.OnMouseLeave(e);
_highlightIndex = -1; SelectedIndex = _committedIndex;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// Perform the select when the mouse is clicked
SelectedIndex = IndexFromPoint(PointToClient(Cursor.Position));
} }
protected override void OnVisibleChanged(EventArgs e) protected override void OnVisibleChanged(EventArgs e)
{ {
base.OnVisibleChanged(e); base.OnVisibleChanged(e);
_highlightIndex = -1; SelectedIndex = _committedIndex;
} }
private void InvalidateItem(int index) protected override void OnMouseDown(MouseEventArgs e)
{ {
if (index < 0 || index >= Items.Count) // Select the item under the mouse and commit
return; SelectedIndex = IndexFromPoint(PointToClient(Cursor.Position));
Invalidate(GetItemRectangle(index)); CommitSelection();
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
// Create a custom event instance to be able to set the selected state for mouse hover
DrawItemState state = e.State;
if (_highlightIndex >= 0)
{
state = _highlightIndex == e.Index ? DrawItemState.Selected : DrawItemState.None;
}
DrawItemEventArgs draw = new DrawItemEventArgs(e.Graphics, e.Font, e.Bounds, e.Index, state);
draw.DrawBackground();
string text = Items[draw.Index].ToString();
using (StringFormat format = new StringFormat())
{
format.LineAlignment = StringAlignment.Center;
using (Brush brush = new SolidBrush(draw.ForeColor))
{
draw.Graphics.DrawString(text,
draw.Font, brush,
draw.Bounds,
format);
}
}
} }
protected override void DefWndProc(ref Message m) protected override void DefWndProc(ref Message m)
@ -117,12 +79,22 @@ namespace Acacia.Controls
Size prefSize = base.GetPreferredSize(proposedSize); Size prefSize = base.GetPreferredSize(proposedSize);
return new Size(prefSize.Width, ItemHeight * Math.Min(Items.Count, _owner.MaxDropDownItems)); return new Size(prefSize.Width, ItemHeight * Math.Min(Items.Count, _owner.MaxDropDownItems));
} }
public void CommitSelection()
{
_committedIndex = SelectedIndex;
base.OnSelectedIndexChanged(new EventArgs());
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
// Don't notify until committed
}
} }
#endregion #endregion
private readonly DropList _list; private readonly DropList _list;
private int _ignoreListEvents;
#region Items properties #region Items properties
@ -162,10 +134,14 @@ namespace Acacia.Controls
private void _list_SelectedIndexChanged(object sender, EventArgs e) private void _list_SelectedIndexChanged(object sender, EventArgs e)
{ {
if (_list.SelectedIndex >= 0 && _ignoreListEvents == 0) if (_list.SelectedIndex >= 0)
{ {
Text = _list.SelectedItem.ToString(); Text = _list.SelectedItem.ToString();
} }
else
{
Text = "";
}
} }
public void BeginUpdate() public void BeginUpdate()
@ -188,17 +164,9 @@ namespace Acacia.Controls
set set
{ {
_list.BindingContext = new BindingContext(); _list.BindingContext = new BindingContext();
++_ignoreListEvents;
try
{
_list.DataSource = value; _list.DataSource = value;
_list.SelectedIndex = -1; _list.SelectedIndex = -1;
} }
finally
{
--_ignoreListEvents;
}
}
} }
protected override int GetDropDownHeightMax() protected override int GetDropDownHeightMax()
@ -219,7 +187,15 @@ namespace Acacia.Controls
case Keys.Down: case Keys.Down:
case Keys.Up: case Keys.Up:
User32.SendMessage(_list.Handle, (int)WM.KEYDOWN, new IntPtr((int)e.KeyCode), IntPtr.Zero); User32.SendMessage(_list.Handle, (int)WM.KEYDOWN, new IntPtr((int)e.KeyCode), IntPtr.Zero);
e.IsInputKey = false; e.IsInputKey = true;
break;
// Enter commits the selected index and closes the drop down
case Keys.Enter:
case Keys.Tab:
_list.CommitSelection();
DroppedDown = false;
e.IsInputKey = e.KeyCode == Keys.Enter;
break; break;
default: default:
base.OnPreviewKeyDown(e); base.OnPreviewKeyDown(e);