Started on combobox fixes for shared folders dialog

This commit is contained in:
Patrick Simpson 2017-06-20 15:26:16 +02:00
parent 833cb6e4d3
commit 03e27943f6
11 changed files with 951 additions and 194 deletions

View File

@ -207,6 +207,9 @@
<Compile Include="AcaciaOptionAttribute.cs" />
<Compile Include="Config.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Controls\KAbstractComboBox.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Controls\KAnimator.cs">
<SubType>Component</SubType>
</Compile>
@ -242,6 +245,9 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="Controls\KSelectionManager.cs" />
<Compile Include="Controls\KTextBox.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Controls\KTreeNode.cs" />
<Compile Include="Controls\KTreeNodeLoader.cs" />
<Compile Include="Controls\KTreeNodes.cs" />
@ -325,6 +331,7 @@
<Compile Include="Native\MAPI\Restriction.cs" />
<Compile Include="Native\MAPI\RestrictionEncoder.cs" />
<Compile Include="Native\UXTheme.cs" />
<Compile Include="Native\VirtualKeys.cs" />
<Compile Include="OutlookConstants.cs" />
<Compile Include="SearchQuery.cs" />
<Compile Include="Stubs\Enums.cs" />

View File

@ -0,0 +1,332 @@
using Acacia.Native;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Acacia.Controls
{
public abstract class KAbstractComboBox : UserControl, IMessageFilter
{
#region Components
private KTextBox _edit;
#endregion
#region Init
public KAbstractComboBox()
{
SetupRenderer();
_edit = new KTextBox();
_edit.BorderStyle = BorderStyle.None;
_edit.Placeholder = "Test";
Controls.Add(_edit);
_state.AddControl(_edit);
_edit.TextChanged += _edit_TextChanged;
}
#endregion
#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; }
}
public void FocusEdit()
{
_edit.Select();
}
#endregion
#region Drop down
public Control DropControl
{
get
{
return _dropControl;
}
set
{
_dropControl = value;
SetupDropDown();
}
}
private ToolStripDropDown _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;
_dropDown = new ToolStripDropDown();
_dropDown.Padding = new Padding(0);
_dropDown.Margin = new Padding(0);
_dropDown.AutoSize = true;
_dropDown.DropShadowEnabled = false;
_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:
System.Diagnostics.Trace.WriteLine("KEYMESSAGE: " + m);
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;
}
break;
case WM.CHAR:
case WM.KEYUP:
System.Diagnostics.Trace.WriteLine("KEYMESSAGE: " + 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;
}
// Cannot use visibility of _dropDown to keep the open state, as clicking on the button already
// hides the popup before the event handler is shown.
private bool _isDroppedDown;
private bool _clickedButton;
private void _dropDown_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
/*if (_stateButton.IsMouseOver)
{
_clickedButton = true;
}*/
_isDroppedDown = false;
}
private void Button_Clicked()
{
/*if (_clickedButton)
_clickedButton = false;
else
DroppedDown = true;*/
DroppedDown = !DroppedDown;
this._edit.Focus();
}
public bool DroppedDown
{
get
{
return _isDroppedDown;
}
set
{
if (value != _isDroppedDown)
{
if (value)
{
_dropListHost.Control.Width = this.Width;
_dropListHost.Control.Height = 200;
_dropListHost.Control.Refresh();
_dropDown.Show(this.PointToScreen(new Point(0, Height)));
_dropDown.Capture = true;
}
else
{
_dropDown.Close();
}
_isDroppedDown = value;
}
}
}
#endregion
#region Rendering
private enum State
{
// Values match those defined in vsstyles.h so no conversion is needed.
Normal = 1, Hot = 2, Pressed = 3, Disabled = 4
}
private KVisualStyle<COMBOBOXPARTS, State> _style = new KVisualStyle<COMBOBOXPARTS, State>("COMBOBOX");
// Enum from vsstyles.h
enum COMBOBOXPARTS
{
CP_DROPDOWNBUTTON = 1,
CP_BACKGROUND = 2,
CP_TRANSPARENTBACKGROUND = 3,
CP_BORDER = 4,
CP_READONLY = 5,
CP_DROPDOWNBUTTONRIGHT = 6,
CP_DROPDOWNBUTTONLEFT = 7,
CP_CUEBANNER = 8,
};
private KVisualStateTracker<State> _state;
private KVisualStateTracker<State>.Part _stateButton;
public void SetupRenderer(bool enableVisualStyles = true)
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ContainerControl, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.Selectable, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.UserMouse, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.Selectable, true);
_style[COMBOBOXPARTS.CP_DROPDOWNBUTTON].SetPadding(COMBOBOXPARTS.CP_DROPDOWNBUTTONLEFT,
COMBOBOXPARTS.CP_DROPDOWNBUTTONRIGHT);
_state = new KVisualStateTracker<State>(this, State.Normal, State.Disabled);
_state.Root.WithHot(State.Hot);
_state.Root.WithFocus(State.Hot);
_stateButton = _state.Root.AddPart().WithPressed(State.Pressed);
_stateButton.Clicked += Button_Clicked;
// TODO if (enableVisualStyles && Application.RenderWithVisualStyles)
}
protected override void OnPaint(PaintEventArgs e)
{
_style[COMBOBOXPARTS.CP_BORDER]?.DrawBackground(e.Graphics, _state.Root.State, ClientRectangle);
_style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.DrawBackground(e.Graphics, _stateButton.State, _stateButton.Rectangle);
}
#endregion
#region Layout
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
using (Graphics graphics = CreateGraphics())
{
// Determine the border insets
Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
// Determine the button size
Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
if (!buttonSize.HasValue)
buttonSize = new Size(ClientRectangle.Height, ClientRectangle.Height);
Rectangle buttonRect = new Rectangle();
buttonRect.X = ClientRectangle.Width - buttonSize.Value.Width;
buttonRect.Width = buttonSize.Value.Width;
buttonRect.Y = 0;
buttonRect.Height = ClientRectangle.Height;
_stateButton.Rectangle = buttonRect;
// Set the edit control
Rectangle editRect = new Rectangle(insets.Left + 2, insets.Top, buttonRect.X - insets.Left - 2,
ClientRectangle.Height - insets.Vertical);
editRect = editRect.CenterVertically(new Size(editRect.Width, _edit.PreferredHeight));
_edit.SetBounds(editRect.X, editRect.Y, editRect.Width, editRect.Height);
}
}
public override Size GetPreferredSize(Size proposedSize)
{
// TODO: cache sizes?
using (Graphics graphics = CreateGraphics())
{
Size editSize = _edit.GetPreferredSize(proposedSize);
Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
Size prefSize = editSize.Expand(insets);
Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
if (!buttonSize.HasValue)
buttonSize = new Size(prefSize.Height, prefSize.Height);
return new Size(prefSize.Width + buttonSize.Value.Width, Math.Max(prefSize.Height, buttonSize.Value.Height));
}
}
#endregion
}
}

View File

@ -8,161 +8,40 @@ using System.Windows.Forms;
namespace Acacia.Controls
{
public class KComboBox : UserControl
public class KComboBox : KAbstractComboBox
{
#region Properties
public ComboBoxStyle DropDownStyle
{
get;
set;
}
public string DisplayMember
{
get;
set;
}
#endregion
#region Components
private TextBox _edit;
#endregion
#region Init
private readonly ListBox _dropList;
public KComboBox()
{
SetupRenderer();
_edit = new TextBox();
_edit.BorderStyle = BorderStyle.None;
Controls.Add(_edit);
_state.AddControl(_edit);
_dropList = new ListBox();
_dropList.IntegralHeight = true;
DropControl = _dropList;
_dropList.DisplayMember = "DisplayName"; // TODO: remove from here
}
#endregion
#region Drop down
private void Button_Clicked()
public void BeginUpdate()
{
_dropList.BeginUpdate();
}
#endregion
#region Rendering
private enum State
public void EndUpdate()
{
// Values match those defined in vsstyles.h so no conversion is needed.
Normal = 1, Hot = 2, Pressed = 3, Disabled = 4
_dropList.EndUpdate();
}
private KVisualStyle<COMBOBOXPARTS, State> _style = new KVisualStyle<COMBOBOXPARTS, State>("COMBOBOX");
// Enum from vsstyles.h
enum COMBOBOXPARTS
public object DataSource
{
CP_DROPDOWNBUTTON = 1,
CP_BACKGROUND = 2,
CP_TRANSPARENTBACKGROUND = 3,
CP_BORDER = 4,
CP_READONLY = 5,
CP_DROPDOWNBUTTONRIGHT = 6,
CP_DROPDOWNBUTTONLEFT = 7,
CP_CUEBANNER = 8,
};
private KVisualStateTracker<State> _state;
private KVisualStateTracker<State>.Part _stateButton;
public void SetupRenderer(bool enableVisualStyles = true)
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ContainerControl, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.Selectable, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.UserMouse, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.Selectable, true);
_style[COMBOBOXPARTS.CP_DROPDOWNBUTTON].SetPadding(COMBOBOXPARTS.CP_DROPDOWNBUTTONLEFT,
COMBOBOXPARTS.CP_DROPDOWNBUTTONRIGHT);
_state = new KVisualStateTracker<State>(this, State.Normal, State.Disabled);
_state.Root.WithHot(State.Hot);
_state.Root.WithFocus(State.Hot);
_stateButton = _state.Root.AddPart().WithPressed(State.Pressed);
_stateButton.Clicked += Button_Clicked;
// TODO if (enableVisualStyles && Application.RenderWithVisualStyles)
}
protected override void OnPaint(PaintEventArgs e)
{
_style[COMBOBOXPARTS.CP_BORDER]?.DrawBackground(e.Graphics, _state.Root.State, ClientRectangle);
_style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.DrawBackground(e.Graphics, _stateButton.State, _stateButton.Rectangle);
}
#endregion
#region Layout
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
using (Graphics graphics = CreateGraphics())
get
{
// Determine the border insets
Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
return _dropList.DataSource;
}
// Determine the button size
Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
if (!buttonSize.HasValue)
buttonSize = new Size(ClientRectangle.Height, ClientRectangle.Height);
Rectangle buttonRect = new Rectangle();
buttonRect.X = ClientRectangle.Width - buttonSize.Value.Width;
buttonRect.Width = buttonSize.Value.Width;
buttonRect.Y = 0;
buttonRect.Height = ClientRectangle.Height;
_stateButton.Rectangle = buttonRect;
// Set the edit control
Rectangle editRect = new Rectangle(insets.Left, insets.Top, buttonRect.X - insets.Left,
ClientRectangle.Height - insets.Vertical);
editRect = editRect.CenterVertically(new Size(editRect.Width, _edit.PreferredHeight));
_edit.SetBounds(editRect.X, editRect.Y, editRect.Width, editRect.Height);
set
{
_dropList.BindingContext = new BindingContext();
_dropList.DataSource = value;
}
}
public override Size GetPreferredSize(Size proposedSize)
{
// TODO: cache sizes?
using (Graphics graphics = CreateGraphics())
{
Size editSize = _edit.GetPreferredSize(proposedSize);
Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
Size prefSize = editSize.Expand(insets);
Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
if (!buttonSize.HasValue)
buttonSize = new Size(prefSize.Height, prefSize.Height);
return new Size(prefSize.Width + buttonSize.Value.Width, Math.Max(prefSize.Height, buttonSize.Value.Height));
}
}
#endregion
}
}

View File

@ -0,0 +1,100 @@
using Acacia.Native;
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 KTextBox : TextBox
{
/// <summary>
/// Label for the placeholder. Returns HTTRANSPARANT for all hit tests, to allow mouse events to pass through
/// </summary>
public class PlaceholderLabel : Label
{
public PlaceholderLabel()
{
BackColor = Color.Transparent;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WM.NCHITTEST)
{
m.Result = new IntPtr(-1); // HTTRANSPARANT
}
else
{
base.WndProc(ref m);
}
}
protected override void OnPaint(PaintEventArgs e)
{
using (Brush brush = new SolidBrush(ForeColor))
{
// Draw outside the label to adjust for the offset below
e.Graphics.DrawString(Text, Font, brush, -2, 0);
}
}
}
#region Properties
private PlaceholderLabel _placeHolderLabel;
public string Placeholder
{
get { return _placeHolderLabel.Text; }
set { _placeHolderLabel.Text = value; CheckPlaceholder(); }
}
public Color PlaceholderColor
{
get { return _placeHolderLabel.ForeColor; }
set { _placeHolderLabel.ForeColor = value; }
}
public Font PlaceholderFont
{
get { return _placeHolderLabel.Font; }
set { _placeHolderLabel.Font = value; }
}
#endregion
public KTextBox()
{
_placeHolderLabel = new PlaceholderLabel();
_placeHolderLabel.Visible = false;
_placeHolderLabel.Margin = new Padding(0);
_placeHolderLabel.Padding = new Padding(0);
Controls.Add(_placeHolderLabel);
PlaceholderColor = Color.Gray;
CheckPlaceholder();
}
private void CheckPlaceholder()
{
bool wantPlaceholder = !string.IsNullOrEmpty(Placeholder) && Text.Length == 0;
_placeHolderLabel.Visible = wantPlaceholder;
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
CheckPlaceholder();
}
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
// The 1 X coordinate is so that the cart is visible
_placeHolderLabel.SetBounds(1, 0, Width, Height);
}
}
}

View File

@ -139,6 +139,10 @@ namespace Acacia.Controls
}
}
}
public bool IsMouseOver
{
get { return _mouseOver; }
}
private bool MousePressed
{

View File

@ -46,9 +46,9 @@
this.checkSendAs = new System.Windows.Forms.CheckBox();
this._labelPermissions = new System.Windows.Forms.Label();
this.labelPermissionsValue = new System.Windows.Forms.Label();
this.dialogButtons = new Acacia.Controls.KDialogButtons();
this._labelReminders = new System.Windows.Forms.Label();
this.checkReminders = new System.Windows.Forms.CheckBox();
this.dialogButtons = new Acacia.Controls.KDialogButtons();
this._layout.SuspendLayout();
this._mainBusyHider.SuspendLayout();
this._layoutMain.SuspendLayout();
@ -109,10 +109,12 @@
//
// gabLookup
//
this.gabLookup.DisplayMember = "DisplayName";
this.gabLookup.DataSource = null;
resources.ApplyResources(this.gabLookup, "gabLookup");
this.gabLookup.DroppedDown = false;
this.gabLookup.GAB = null;
this.gabLookup.Name = "gabLookup";
this.gabLookup.SelectedUser = null;
this.gabLookup.SelectedUserChanged += new Acacia.UI.GABLookupControl.SelectedUserEventHandler(this.gabLookup_SelectedUserChanged);
//
// kTreeFolders
@ -178,16 +180,6 @@
resources.ApplyResources(this.labelPermissionsValue, "labelPermissionsValue");
this.labelPermissionsValue.Name = "labelPermissionsValue";
//
// dialogButtons
//
resources.ApplyResources(this.dialogButtons, "dialogButtons");
this.dialogButtons.ButtonSize = null;
this.dialogButtons.Cancellation = null;
this.dialogButtons.HasApply = true;
this.dialogButtons.IsDirty = false;
this.dialogButtons.Name = "dialogButtons";
this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply);
//
// _labelReminders
//
resources.ApplyResources(this._labelReminders, "_labelReminders");
@ -200,6 +192,16 @@
this.checkReminders.UseVisualStyleBackColor = true;
this.checkReminders.CheckedChanged += new System.EventHandler(this.checkReminders_CheckedChanged);
//
// dialogButtons
//
resources.ApplyResources(this.dialogButtons, "dialogButtons");
this.dialogButtons.ButtonSize = null;
this.dialogButtons.Cancellation = null;
this.dialogButtons.HasApply = true;
this.dialogButtons.IsDirty = false;
this.dialogButtons.Name = "dialogButtons";
this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply);
//
// SharedFoldersDialog
//
resources.ApplyResources(this, "$this");

View File

@ -222,9 +222,6 @@
<data name="gabLookup.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="gabLookup.FlatStyle" type="System.Windows.Forms.FlatStyle, System.Windows.Forms">
<value>Popup</value>
</data>
<data name="gabLookup.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 3</value>
</data>
@ -235,7 +232,7 @@
<value>256, 21</value>
</data>
<data name="gabLookup.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
<value>0</value>
</data>
<data name="&gt;&gt;gabLookup.Name" xml:space="preserve">
<value>gabLookup</value>
@ -310,7 +307,7 @@
<value>0</value>
</data>
<data name="_layoutSelectUser.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /&gt;&lt;Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /&gt;&lt;Rows Styles="Percent,100,Absolute,27" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /&gt;&lt;Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /&gt;&lt;Rows Styles="Percent,100,Absolute,31" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="kTreeFolders.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
@ -322,7 +319,7 @@
<value>442, 275</value>
</data>
<data name="kTreeFolders.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
<value>0</value>
</data>
<data name="&gt;&gt;kTreeFolders.Name" xml:space="preserve">
<value>kTreeFolders</value>
@ -391,7 +388,7 @@
<value>351, 20</value>
</data>
<data name="textName.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
<value>0</value>
</data>
<data name="&gt;&gt;textName.Name" xml:space="preserve">
<value>textName</value>
@ -721,7 +718,7 @@
<value>450, 35</value>
</data>
<data name="dialogButtons.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
<value>0</value>
</data>
<data name="&gt;&gt;dialogButtons.Name" xml:space="preserve">
<value>dialogButtons</value>

View File

@ -48,6 +48,8 @@ namespace Acacia.Native
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, GWL gwl);
#region Geometry
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
@ -73,6 +75,11 @@ namespace Acacia.Native
return rect.ToRectangle();
}
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref Point pt, int cPoints);
#endregion
#region Messages
[DllImport("user32.dll")]

View File

@ -0,0 +1,405 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acacia.Native
{
// Form pinvoke.net
public enum VirtualKeys : ushort
{
/// <summary></summary>
LeftButton = 0x01,
/// <summary></summary>
RightButton = 0x02,
/// <summary></summary>
Cancel = 0x03,
/// <summary></summary>
MiddleButton = 0x04,
/// <summary></summary>
ExtraButton1 = 0x05,
/// <summary></summary>
ExtraButton2 = 0x06,
/// <summary></summary>
Back = 0x08,
/// <summary></summary>
Tab = 0x09,
/// <summary></summary>
Clear = 0x0C,
/// <summary></summary>
Return = 0x0D,
/// <summary></summary>
Shift = 0x10,
/// <summary></summary>
Control = 0x11,
/// <summary></summary>
Menu = 0x12,
/// <summary></summary>
Pause = 0x13,
/// <summary></summary>
CapsLock = 0x14,
/// <summary></summary>
Kana = 0x15,
/// <summary></summary>
Hangeul = 0x15,
/// <summary></summary>
Hangul = 0x15,
/// <summary></summary>
Junja = 0x17,
/// <summary></summary>
Final = 0x18,
/// <summary></summary>
Hanja = 0x19,
/// <summary></summary>
Kanji = 0x19,
/// <summary></summary>
Escape = 0x1B,
/// <summary></summary>
Convert = 0x1C,
/// <summary></summary>
NonConvert = 0x1D,
/// <summary></summary>
Accept = 0x1E,
/// <summary></summary>
ModeChange = 0x1F,
/// <summary></summary>
Space = 0x20,
/// <summary></summary>
Prior = 0x21,
/// <summary></summary>
Next = 0x22,
/// <summary></summary>
End = 0x23,
/// <summary></summary>
Home = 0x24,
/// <summary></summary>
Left = 0x25,
/// <summary></summary>
Up = 0x26,
/// <summary></summary>
Right = 0x27,
/// <summary></summary>
Down = 0x28,
/// <summary></summary>
Select = 0x29,
/// <summary></summary>
Print = 0x2A,
/// <summary></summary>
Execute = 0x2B,
/// <summary></summary>
Snapshot = 0x2C,
/// <summary></summary>
Insert = 0x2D,
/// <summary></summary>
Delete = 0x2E,
/// <summary></summary>
Help = 0x2F,
/// <summary></summary>
N0 = 0x30,
/// <summary></summary>
N1 = 0x31,
/// <summary></summary>
N2 = 0x32,
/// <summary></summary>
N3 = 0x33,
/// <summary></summary>
N4 = 0x34,
/// <summary></summary>
N5 = 0x35,
/// <summary></summary>
N6 = 0x36,
/// <summary></summary>
N7 = 0x37,
/// <summary></summary>
N8 = 0x38,
/// <summary></summary>
N9 = 0x39,
/// <summary></summary>
A = 0x41,
/// <summary></summary>
B = 0x42,
/// <summary></summary>
C = 0x43,
/// <summary></summary>
D = 0x44,
/// <summary></summary>
E = 0x45,
/// <summary></summary>
F = 0x46,
/// <summary></summary>
G = 0x47,
/// <summary></summary>
H = 0x48,
/// <summary></summary>
I = 0x49,
/// <summary></summary>
J = 0x4A,
/// <summary></summary>
K = 0x4B,
/// <summary></summary>
L = 0x4C,
/// <summary></summary>
M = 0x4D,
/// <summary></summary>
N = 0x4E,
/// <summary></summary>
O = 0x4F,
/// <summary></summary>
P = 0x50,
/// <summary></summary>
Q = 0x51,
/// <summary></summary>
R = 0x52,
/// <summary></summary>
S = 0x53,
/// <summary></summary>
T = 0x54,
/// <summary></summary>
U = 0x55,
/// <summary></summary>
V = 0x56,
/// <summary></summary>
W = 0x57,
/// <summary></summary>
X = 0x58,
/// <summary></summary>
Y = 0x59,
/// <summary></summary>
Z = 0x5A,
/// <summary></summary>
LeftWindows = 0x5B,
/// <summary></summary>
RightWindows = 0x5C,
/// <summary></summary>
Application = 0x5D,
/// <summary></summary>
Sleep = 0x5F,
/// <summary></summary>
Numpad0 = 0x60,
/// <summary></summary>
Numpad1 = 0x61,
/// <summary></summary>
Numpad2 = 0x62,
/// <summary></summary>
Numpad3 = 0x63,
/// <summary></summary>
Numpad4 = 0x64,
/// <summary></summary>
Numpad5 = 0x65,
/// <summary></summary>
Numpad6 = 0x66,
/// <summary></summary>
Numpad7 = 0x67,
/// <summary></summary>
Numpad8 = 0x68,
/// <summary></summary>
Numpad9 = 0x69,
/// <summary></summary>
Multiply = 0x6A,
/// <summary></summary>
Add = 0x6B,
/// <summary></summary>
Separator = 0x6C,
/// <summary></summary>
Subtract = 0x6D,
/// <summary></summary>
Decimal = 0x6E,
/// <summary></summary>
Divide = 0x6F,
/// <summary></summary>
F1 = 0x70,
/// <summary></summary>
F2 = 0x71,
/// <summary></summary>
F3 = 0x72,
/// <summary></summary>
F4 = 0x73,
/// <summary></summary>
F5 = 0x74,
/// <summary></summary>
F6 = 0x75,
/// <summary></summary>
F7 = 0x76,
/// <summary></summary>
F8 = 0x77,
/// <summary></summary>
F9 = 0x78,
/// <summary></summary>
F10 = 0x79,
/// <summary></summary>
F11 = 0x7A,
/// <summary></summary>
F12 = 0x7B,
/// <summary></summary>
F13 = 0x7C,
/// <summary></summary>
F14 = 0x7D,
/// <summary></summary>
F15 = 0x7E,
/// <summary></summary>
F16 = 0x7F,
/// <summary></summary>
F17 = 0x80,
/// <summary></summary>
F18 = 0x81,
/// <summary></summary>
F19 = 0x82,
/// <summary></summary>
F20 = 0x83,
/// <summary></summary>
F21 = 0x84,
/// <summary></summary>
F22 = 0x85,
/// <summary></summary>
F23 = 0x86,
/// <summary></summary>
F24 = 0x87,
/// <summary></summary>
NumLock = 0x90,
/// <summary></summary>
ScrollLock = 0x91,
/// <summary></summary>
NEC_Equal = 0x92,
/// <summary></summary>
Fujitsu_Jisho = 0x92,
/// <summary></summary>
Fujitsu_Masshou = 0x93,
/// <summary></summary>
Fujitsu_Touroku = 0x94,
/// <summary></summary>
Fujitsu_Loya = 0x95,
/// <summary></summary>
Fujitsu_Roya = 0x96,
/// <summary></summary>
LeftShift = 0xA0,
/// <summary></summary>
RightShift = 0xA1,
/// <summary></summary>
LeftControl = 0xA2,
/// <summary></summary>
RightControl = 0xA3,
/// <summary></summary>
LeftMenu = 0xA4,
/// <summary></summary>
RightMenu = 0xA5,
/// <summary></summary>
BrowserBack = 0xA6,
/// <summary></summary>
BrowserForward = 0xA7,
/// <summary></summary>
BrowserRefresh = 0xA8,
/// <summary></summary>
BrowserStop = 0xA9,
/// <summary></summary>
BrowserSearch = 0xAA,
/// <summary></summary>
BrowserFavorites = 0xAB,
/// <summary></summary>
BrowserHome = 0xAC,
/// <summary></summary>
VolumeMute = 0xAD,
/// <summary></summary>
VolumeDown = 0xAE,
/// <summary></summary>
VolumeUp = 0xAF,
/// <summary></summary>
MediaNextTrack = 0xB0,
/// <summary></summary>
MediaPrevTrack = 0xB1,
/// <summary></summary>
MediaStop = 0xB2,
/// <summary></summary>
MediaPlayPause = 0xB3,
/// <summary></summary>
LaunchMail = 0xB4,
/// <summary></summary>
LaunchMediaSelect = 0xB5,
/// <summary></summary>
LaunchApplication1 = 0xB6,
/// <summary></summary>
LaunchApplication2 = 0xB7,
/// <summary></summary>
OEM1 = 0xBA,
/// <summary></summary>
OEMPlus = 0xBB,
/// <summary></summary>
OEMComma = 0xBC,
/// <summary></summary>
OEMMinus = 0xBD,
/// <summary></summary>
OEMPeriod = 0xBE,
/// <summary></summary>
OEM2 = 0xBF,
/// <summary></summary>
OEM3 = 0xC0,
/// <summary></summary>
OEM4 = 0xDB,
/// <summary></summary>
OEM5 = 0xDC,
/// <summary></summary>
OEM6 = 0xDD,
/// <summary></summary>
OEM7 = 0xDE,
/// <summary></summary>
OEM8 = 0xDF,
/// <summary></summary>
OEMAX = 0xE1,
/// <summary></summary>
OEM102 = 0xE2,
/// <summary></summary>
ICOHelp = 0xE3,
/// <summary></summary>
ICO00 = 0xE4,
/// <summary></summary>
ProcessKey = 0xE5,
/// <summary></summary>
ICOClear = 0xE6,
/// <summary></summary>
Packet = 0xE7,
/// <summary></summary>
OEMReset = 0xE9,
/// <summary></summary>
OEMJump = 0xEA,
/// <summary></summary>
OEMPA1 = 0xEB,
/// <summary></summary>
OEMPA2 = 0xEC,
/// <summary></summary>
OEMPA3 = 0xED,
/// <summary></summary>
OEMWSCtrl = 0xEE,
/// <summary></summary>
OEMCUSel = 0xEF,
/// <summary></summary>
OEMATTN = 0xF0,
/// <summary></summary>
OEMFinish = 0xF1,
/// <summary></summary>
OEMCopy = 0xF2,
/// <summary></summary>
OEMAuto = 0xF3,
/// <summary></summary>
OEMENLW = 0xF4,
/// <summary></summary>
OEMBackTab = 0xF5,
/// <summary></summary>
ATTN = 0xF6,
/// <summary></summary>
CRSel = 0xF7,
/// <summary></summary>
EXSel = 0xF8,
/// <summary></summary>
EREOF = 0xF9,
/// <summary></summary>
Play = 0xFA,
/// <summary></summary>
Zoom = 0xFB,
/// <summary></summary>
Noname = 0xFC,
/// <summary></summary>
PA1 = 0xFD,
/// <summary></summary>
OEMClear = 0xFE
}
}

View File

@ -25,6 +25,20 @@ namespace Acacia.Native
{
public enum WM : int
{
NCHITTEST = 0x0084,
NCPAINT = 0x0085,
NCLBUTTONDOWN = 0x00A1,
NCRBUTTONDOWN = 0x00A4,
NCMBUTTONDOWN = 0x00A7,
KEYDOWN = 0x0100,
KEYUP = 0x0101,
CHAR = 0x0102,
LBUTTONDOWN = 0x0201,
RBUTTONDOWN = 0x0204,
MBUTTONDOWN = 0x0207
}
}

View File

@ -27,10 +27,11 @@ using Acacia.ZPush;
using Acacia.Features.GAB;
using Acacia.Stubs;
using System.Collections;
using Acacia.Controls;
namespace Acacia.UI
{
public partial class GABLookupControl : ComboBox
public partial class GABLookupControl : KComboBox
{
public GABLookupControl() : this(null)
{
@ -39,14 +40,12 @@ namespace Acacia.UI
public GABLookupControl(GABHandler gab)
{
InitializeComponent();
DropDownStyle = ComboBoxStyle.DropDown;
DisplayMember = "DisplayName";
this.GAB = gab;
}
#region Properties and events
#region SelectedUser
#region SelectedUser
public class SelectedUserEventArgs : EventArgs
{
@ -69,14 +68,15 @@ namespace Acacia.UI
{
get
{
if (SelectedValue == null)
/*if (SelectedValue == null)
return new GABUser(Text, Text);
else
return (GABUser)SelectedValue;
return (GABUser)SelectedValue;*/
return null;
}
set
{
if (value == null)
/*if (value == null)
{
SelectedIndex = -1;
Text = "";
@ -84,7 +84,7 @@ namespace Acacia.UI
else
{
}
}*/
}
}
@ -112,7 +112,14 @@ namespace Acacia.UI
public GABHandler GAB
{
get { return _gab; }
set { _gab = value; }
set
{
if (_gab != value)
{
_gab = value;
LookupUsers(false);
}
}
}
#endregion
@ -121,13 +128,13 @@ namespace Acacia.UI
protected override void OnTextChanged(EventArgs e)
{
LookupUsers();
LookupUsers(true);
SelectCurrentUser(false);
}
private void SelectCurrentUser(bool isChosen)
{
GABUser user = null;
/*GABUser user = null;
// Select whatever is currently in the text box as a user
if (DataSource != null)
{
@ -139,10 +146,10 @@ namespace Acacia.UI
// Make a new one
user = new GABUser(Text, Text);
}
SetSelectedUser(user, isChosen);
SetSelectedUser(user, isChosen);*/
}
private bool _needUpdate;
/*private bool _needUpdate;
protected override void OnTextUpdate(EventArgs e)
{
@ -171,34 +178,36 @@ namespace Acacia.UI
protected override void OnDataSourceChanged(EventArgs e)
{
// Suppress to prevent automatic selection
}
}*/
private string _lastText;
private List<GABUser> _allUsers;
private void LookupUsers()
private void LookupUsers(bool dropDown)
{
// Cannot lookup if there is no GAB
if (_gab == null)
return;
if (!_needUpdate)
return;
_needUpdate = false;
string text = this.Text;
// Only search if there is text
if (text.Length == 0)
{
DataSource = null;
DroppedDown = false;
_lastText = "";
return;
}
// Only search if the text actually changed
if (_lastText != text)
{
List<GABUser> users = Lookup(text, 5);
// Limit search results if there is a filter, otherwise show everything
List<GABUser> users;
if (text.Length == 0)
{
// Cache the list of all users
if (_allUsers == null)
{
_allUsers = Lookup("", int.MaxValue);
}
users = _allUsers;
}
else
{
users = Lookup(text, 8);
}
// Sort the users if we have them
users.Sort();
@ -208,12 +217,13 @@ namespace Acacia.UI
// Setting the datasource will trigger a select if there is a match
BeginUpdate();
DataSource = users;
SetItemsCore(users);
DroppedDown = true;
Cursor.Current = Cursors.Default;
Text = _lastText;
SelectionLength = 0;
SelectionStart = _lastText.Length;
//SetItemsCore(users);
if (dropDown)
DroppedDown = true;
//Cursor.Current = Cursors.Default;
//Text = _lastText;
//SelectionLength = 0;
//SelectionStart = _lastText.Length;
EndUpdate();
}
}