diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
index 047bb47..d0e5f88 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
@@ -241,9 +241,6 @@
Component
-
- Component
-
Component
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs
index deb9380..2818a81 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
+ public abstract class KAbstractComboBox : ContainerControl, IMessageFilter
{
#region Properties
@@ -41,6 +41,19 @@ namespace Acacia.Controls
set { _edit.PlaceholderFont = value; }
}
+ protected Control DropControl
+ {
+ get
+ {
+ return _dropControl;
+ }
+ set
+ {
+ _dropControl = value;
+ SetupDropDown();
+ }
+ }
+
#endregion
@@ -64,8 +77,28 @@ namespace Acacia.Controls
_edit.TextChanged += _edit_TextChanged;
_edit.LostFocus += _edit_LostFocus;
_edit.PreviewKeyDown += _edit_PreviewKeyDown;
+ _edit.Leave += _edit_Leave;
+ _edit.Enter += _edit_Enter;
+
+ Application.AddMessageFilter(this);
}
+ private void _edit_Enter(object sender, EventArgs e)
+ {
+ System.Diagnostics.Trace.WriteLine(string.Format("_edit_Enter"));
+ }
+
+ private void _edit_Leave(object sender, EventArgs e)
+ {
+ System.Diagnostics.Trace.WriteLine(string.Format("_edit_Leave"));
+ DroppedDown = false;
+ }
+
+ protected override void OnHandleDestroyed(EventArgs e)
+ {
+ Application.RemoveMessageFilter(this);
+ base.OnHandleDestroyed(e);
+ }
#endregion
@@ -96,7 +129,7 @@ namespace Acacia.Controls
if (DroppedDown)
{
DroppedDown = false;
- e.IsInputKey = false;
+ e.IsInputKey = true;
return;
}
break;
@@ -113,24 +146,10 @@ namespace Acacia.Controls
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;
+ System.Diagnostics.Trace.WriteLine(string.Format("_edit_LostFocus"));
}
protected override void OnGotFocus(EventArgs e)
@@ -148,33 +167,49 @@ namespace Acacia.Controls
#region Drop down
- public Control DropControl
+ private class DropDownRenderer : ToolStripRenderer
{
- get
+ private readonly KVisualStyle.Part _style;
+
+ public DropDownRenderer(KVisualStyle.Part style)
{
- return _dropControl;
+ this._style = style;
}
- set
+
+ protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
- _dropControl = value;
- SetupDropDown();
+ _style.DrawBackground(e.Graphics, State.Pressed, e.AffectedBounds);
}
}
- private ToolStripDropDown _dropDown;
+ private class DropDown : ToolStripDropDown
+ {
+ public DropDown(DropDownRenderer renderer)
+ {
+ Renderer = renderer;
+ }
+ }
+
+ private DropDown _dropDown;
private Control _dropControl;
private ToolStripControlHost _dropListHost;
private void SetupDropDown()
{
_dropListHost = new ToolStripControlHost(_dropControl);
+
_dropListHost.Padding = new Padding(0);
_dropListHost.Margin = new Padding(0);
- _dropListHost.AutoSize = false;
+ _dropListHost.AutoSize = true;
_dropListHost.GotFocus += (s, e) => System.Diagnostics.Trace.WriteLine("_dropListHost.GotFocus");
- _dropDown = new ToolStripDropDown();
+ _dropDown = new DropDown(new DropDownRenderer(_style[COMBOBOXPARTS.CP_BORDER]));
_dropDown.Padding = new Padding(0);
+ using (Graphics graphics = CreateGraphics())
+ {
+ Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, State.Hot) ?? new Padding();
+ _dropDown.Padding = insets;
+ }
_dropDown.Margin = new Padding(0);
_dropDown.AutoSize = true;
_dropDown.DropShadowEnabled = false;
@@ -213,20 +248,27 @@ namespace Acacia.Controls
{
if (value)
{
- // Calculate the height of the control
+ // Calculate the dimensions of the dropdown
int maxHeight = GetDropDownHeightMax();
int minHeight = GetDropDownHeightMin();
- Size prefSize = _dropControl.GetPreferredSize(new Size(Width, maxHeight));
- _dropControl.Width = Util.Bound(prefSize.Width, Width, Width * 2);
- _dropControl.Height = Util.Bound(prefSize.Height, minHeight, maxHeight);
+ //Size prefSize = new Size(minHeight, maxHeight);
+ Size prefSize = _dropControl.GetPreferredSize(new Size(Width - _dropDown.Padding.Horizontal, maxHeight - _dropDown.Padding.Vertical));
+ int width = Util.Bound(prefSize.Width, Width - _dropDown.Padding.Horizontal, Width * 2);
+ int height = Util.Bound(prefSize.Height, minHeight, maxHeight);
+
+ System.Diagnostics.Trace.WriteLine(string.Format("DROPDOWN1: {0} - {1} - {2}", prefSize, width,
+ ((ListBox)_dropControl).ItemHeight));
+ _dropControl.MaximumSize = _dropControl.MinimumSize = new Size(width, height);
+
// Show the drop down below the current control
- _dropDown.Show(this.PointToScreen(new Point(0, Height)));
- _dropControl.Capture = true;
+ _dropDown.Show(this.PointToScreen(new Point(0, Height - 1)));
+ //_dropListHost.Height = _dropDown.Height - _dropDown.Padding.Vertical;
+ System.Diagnostics.Trace.WriteLine(string.Format("DROPDOWN2: {0} - {1} - {2} - {3}: {4}",
+ _dropDown.Width, _dropListHost.Width, _dropControl.Width, width, this.Width));
}
else
{
_dropDown.Close();
- _dropControl.Capture = false;
}
_isDroppedDown = value;
}
@@ -348,5 +390,60 @@ namespace Acacia.Controls
}
#endregion
+
+ #region Message filtering
+
+ public bool PreFilterMessage(ref Message m)
+ {
+ switch ((WM)m.Msg)
+ {
+ case WM.LBUTTONDOWN:
+ case WM.RBUTTONDOWN:
+ case WM.MBUTTONDOWN:
+ return CheckMouseDown(m, false);
+ case WM.NCLBUTTONDOWN:
+ case WM.NCRBUTTONDOWN:
+ case WM.NCMBUTTONDOWN:
+ return CheckMouseDown(m, true);
+
+ }
+ return false;
+ }
+
+ private bool CheckMouseDown(Message m, bool nonClient)
+ {
+ 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);
+ Point ptOrig = pt;
+ if (!nonClient)
+ {
+ // Map to global coordinates
+ User32.MapWindowPoints(m.HWnd, IntPtr.Zero, ref pt, 1);
+ }
+ System.Diagnostics.Trace.WriteLine(string.Format("MOUSE: {0} - {1} - {2}", pt, _dropDown.Bounds, ptOrig));
+ if (!_dropDown.Bounds.Contains(pt))
+ {
+ System.Diagnostics.Trace.WriteLine(string.Format("CONTAINS1"));
+ User32.MapWindowPoints(m.HWnd, Handle, ref pt, 1);
+ if (!ClientRectangle.Contains(pt))
+ {
+ DroppedDown = false;
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ #endregion
+
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
index bc950ca..6de6d78 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
@@ -14,7 +14,111 @@ namespace Acacia.Controls
{
public class KComboBox : KAbstractComboBox
{
- protected readonly KListBox _list;
+ private class KListBox : ListBox
+ {
+ private readonly KComboBox _owner;
+ private int _hoverIndex = -1;
+
+ public KListBox(KComboBox owner)
+ {
+ this._owner = owner;
+ SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+ DrawMode = DrawMode.OwnerDrawFixed;
+ SetStyle(ControlStyles.Selectable, false);
+ //ItemHeight = 23;
+ BorderStyle = BorderStyle.None;
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ 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);
+ }
+ }
+
+ protected override void OnMouseLeave(EventArgs e)
+ {
+ base.OnMouseLeave(e);
+ _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);
+ _hoverIndex = -1;
+ }
+
+ private void InvalidateItem(int index)
+ {
+ if (index < 0 || index >= Items.Count)
+ return;
+ Invalidate(GetItemRectangle(index));
+ }
+
+ 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 (_hoverIndex >= 0)
+ {
+ state = _hoverIndex == 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)
+ {
+ const int WM_MOUSEACTIVATE = 0x21;
+ const int MA_NOACTIVATE = 0x0003;
+
+ switch (m.Msg)
+ {
+ // Prevent mouse activity from grabbing the focus away from the edit
+ case WM_MOUSEACTIVATE:
+ m.Result = (IntPtr)MA_NOACTIVATE;
+ return;
+ }
+ base.DefWndProc(ref m);
+ }
+
+ public override Size GetPreferredSize(Size proposedSize)
+ {
+ Size prefSize = base.GetPreferredSize(proposedSize);
+ return new Size(prefSize.Width, ItemHeight * _owner.MaxDropDownItems);
+ }
+ }
+
+ private readonly KListBox _list;
+ private int _ignoreListEvents;
#region Items properties
@@ -45,7 +149,7 @@ namespace Acacia.Controls
public KComboBox()
{
MaxDropDownItems = 8;
- _list = new KListBox();
+ _list = new KListBox(this);
_list.IntegralHeight = true;
_list.TabStop = false;
DropControl = _list;
@@ -62,7 +166,7 @@ namespace Acacia.Controls
private void _list_SelectedIndexChanged(object sender, EventArgs e)
{
- if (_list.SelectedIndex >= 0)
+ if (_list.SelectedIndex >= 0 && _ignoreListEvents == 0)
{
Text = _list.SelectedItem.ToString();
}
@@ -88,7 +192,16 @@ namespace Acacia.Controls
set
{
_list.BindingContext = new BindingContext();
- _list.DataSource = value;
+ ++_ignoreListEvents;
+ try
+ {
+ _list.DataSource = value;
+ _list.SelectedIndex = -1;
+ }
+ finally
+ {
+ --_ignoreListEvents;
+ }
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs
deleted file mode 100644
index 9738892..0000000
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KListBox.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-namespace Acacia.Controls
-{
- public class KListBox : ListBox
- {
- private int _hoverIndex = -1;
-
- public KListBox()
- {
- SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
- DrawMode = DrawMode.OwnerDrawFixed;
- SetStyle(ControlStyles.Selectable, true);
- }
-
- protected override void OnMouseMove(MouseEventArgs e)
- {
- 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);
- }
- }
-
- protected override void OnMouseLeave(EventArgs e)
- {
- base.OnMouseLeave(e);
- _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);
- _hoverIndex = -1;
- }
-
- private void InvalidateItem(int index)
- {
- if (index < 0)
- return;
- Invalidate(GetItemRectangle(index));
- }
-
- 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 (_hoverIndex >= 0)
- {
- state = _hoverIndex == 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);
- }
- }
- }
- }
-}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs
index d7c5b89..0821ad2 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs
@@ -218,7 +218,7 @@ namespace Acacia.UI
BeginUpdate();
DataSource = users;
//SetItemsCore(users);
- if (dropDown)
+ if (dropDown && text.Length != 0)
DroppedDown = true;
//Cursor.Current = Cursors.Default;
//Text = _lastText;