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:
parent
fdf8350afb
commit
acfc47f018
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user