// Daniel Nauck (dna(at)mono-project(dot)de)
using System;
-using System.Drawing;
using System.Collections;
using System.ComponentModel;
-using System.Reflection;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
+using System.Drawing;
+using System.Globalization;
+using System.Reflection;
using System.Runtime.InteropServices;
-
namespace System.Windows.Forms
{
[DefaultProperty("Items")]
public class ComboBox : ListControl
{
private DrawMode draw_mode = DrawMode.Normal;
- private ComboBoxStyle dropdown_style = (ComboBoxStyle)(-1);
- private int dropdown_width = -1;
+ private ComboBoxStyle dropdown_style;
+ private int dropdown_width = -1;
private int selected_index = -1;
- internal ObjectCollection items = null;
+ private ObjectCollection items;
private bool suspend_ctrlupdate;
- private int maxdrop_items = 8;
+ private int maxdrop_items = 8;
private bool integral_height = true;
private bool sorted;
private int max_length;
- private ComboListBox listbox_ctrl;
+ private ComboListBox listbox_ctrl;
private ComboTextBox textbox_ctrl;
private bool process_textchanged_event = true;
- private bool item_height_specified = false;
+ private bool item_height_specified;
private int item_height;
private int requested_height = -1;
private Hashtable item_heights;
- private bool show_dropdown_button = false;
+ private bool show_dropdown_button;
private ButtonState button_state = ButtonState.Normal;
private bool dropped_down;
private Rectangle text_area;
private Rectangle button_area;
private Rectangle listbox_area;
private const int button_width = 16;
+ bool drop_down_button_entered;
#if NET_2_0
private AutoCompleteStringCollection auto_complete_custom_source = null;
private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
items = new ObjectCollection (this);
DropDownStyle = ComboBoxStyle.DropDown;
item_height = FontHeight + 2;
- BackColor = ThemeEngine.Current.ColorWindow;
+ background_color = ThemeEngine.Current.ColorWindow;
border_style = BorderStyle.None;
#if NET_2_0
MouseDown += new MouseEventHandler (OnMouseDownCB);
MouseUp += new MouseEventHandler (OnMouseUpCB);
MouseMove += new MouseEventHandler (OnMouseMoveCB);
- MouseWheel += new MouseEventHandler (OnMouseWheelCB);
+ MouseWheel += new MouseEventHandler (OnMouseWheelCB);
+ MouseLeave += new EventHandler (OnMouseLeave);
KeyDown +=new KeyEventHandler(OnKeyDownCB);
}
set {
if (base.BackColor == value)
return;
-
- base.BackColor = value;
+ base.BackColor = value;
Refresh ();
}
}
set {
if (base.BackgroundImage == value)
return;
-
- base.BackgroundImage = value;
+ base.BackgroundImage = value;
Refresh ();
}
}
set { base.DataSource = value; }
}
#endif
+
protected override Size DefaultSize {
get { return new Size (121, 21); }
}
[DefaultValue (DrawMode.Normal)]
public DrawMode DrawMode {
get { return draw_mode; }
-
- set {
+ set {
if (!Enum.IsDefined (typeof (DrawMode), value))
throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
if (draw_mode == DrawMode.OwnerDrawVariable)
item_heights = null;
- draw_mode = value;
+ draw_mode = value;
if (draw_mode == DrawMode.OwnerDrawVariable)
item_heights = new Hashtable ();
Refresh ();
- }
+ }
}
#if NET_2_0
[RefreshProperties(RefreshProperties.Repaint)]
public ComboBoxStyle DropDownStyle {
get { return dropdown_style; }
-
- set {
-
+ set {
if (!Enum.IsDefined (typeof (ComboBoxStyle), value))
throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value));
if (dropdown_style == value)
- return;
+ return;
SuspendLayout ();
if (dropdown_style == ComboBoxStyle.Simple) {
- if (listbox_ctrl != null) {
+ if (listbox_ctrl != null) {
Controls.RemoveImplicit (listbox_ctrl);
- listbox_ctrl.Dispose ();
+ listbox_ctrl.Dispose ();
listbox_ctrl = null;
}
}
- dropdown_style = value;
+ dropdown_style = value;
if (dropdown_style == ComboBoxStyle.DropDownList && textbox_ctrl != null) {
Controls.RemoveImplicit (textbox_ctrl);
- textbox_ctrl.Dispose ();
- textbox_ctrl = null;
- }
+ textbox_ctrl.Dispose ();
+ textbox_ctrl = null;
+ }
if (dropdown_style == ComboBoxStyle.Simple) {
- show_dropdown_button = false;
+ show_dropdown_button = false;
CreateComboListBox ();
-
- if (IsHandleCreated) {
- Controls.AddImplicit (listbox_ctrl);
- listbox_ctrl.Visible = true;
- }
+ Controls.AddImplicit (listbox_ctrl);
+ listbox_ctrl.Visible = true;
+
+ // This should give us a 150 default height
+ // for Simple mode if size hasn't been set
+ // (DefaultSize doesn't work for us in this case)
+ if (requested_height == -1)
+ requested_height = 150;
} else {
show_dropdown_button = true;
button_state = ButtonState.Normal;
- }
+ }
if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) {
textbox_ctrl = new ComboTextBox (this);
textbox_ctrl.Text = GetItemText (selected_item);
textbox_ctrl.BorderStyle = BorderStyle.None;
textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
+ textbox_ctrl.KeyPress += new KeyPressEventHandler (OnTextKeyPress);
textbox_ctrl.Click += new EventHandler (OnTextBoxClick);
+ textbox_ctrl.ContextMenu = ContextMenu;
- if (IsHandleCreated == true) {
+ if (IsHandleCreated == true)
Controls.AddImplicit (textbox_ctrl);
- }
}
ResumeLayout ();
OnDropDownStyleChanged (EventArgs.Empty);
-
+
LayoutComboBox ();
UpdateComboBoxBounds ();
Refresh ();
- }
+ }
}
public int DropDownWidth {
else
listbox_ctrl.Hide ();
}
- }
+ }
#if NET_2_0
[DefaultValue (FlatStyle.Standard)]
Invalidate ();
}
}
-
-
#endif
public override bool Focused {
set {
if (base.ForeColor == value)
return;
-
- base.ForeColor = value;
+ base.ForeColor = value;
Refresh ();
}
}
[DefaultValue (true)]
- [Localizable (true)]
+ [Localizable (true)]
public bool IntegralHeight {
get { return integral_height; }
set {
if (integral_height == value)
return;
-
- integral_height = value;
+ integral_height = value;
UpdateComboBoxBounds ();
- Refresh ();
+ Refresh ();
}
}
public int ItemHeight {
get {
if (item_height == -1) {
- SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
+ SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
item_height = (int) sz.Height;
}
return item_height;
set {
if (maxdrop_items == value)
return;
-
- maxdrop_items = value;
+ maxdrop_items = value;
}
}
}
}
#endif
+
[DefaultValue (0)]
[Localizable (true)]
public int MaxLength {
max_length = value;
if (dropdown_style != ComboBoxStyle.DropDownList) {
-
if (value < 0) {
value = 0;
}
-
textbox_ctrl.MaxLength = value;
- }
+ }
}
}
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- [Browsable (false)]
+ [Browsable (false)]
public int PreferredHeight {
get {
- return ItemHeight + 5;
+ return ItemHeight + 6;
}
}
return;
if (value <= -2 || value >= Items.Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
- selected_index = value;
+ throw new ArgumentOutOfRangeException ("SelectedIndex");
+ selected_index = value;
- if (dropdown_style != ComboBoxStyle.DropDownList) {
+ if (dropdown_style != ComboBoxStyle.DropDownList) {
if (value == -1)
SetControlText("");
else
SetControlText (GetItemText (Items [value]));
- }
+ }
if (DropDownStyle == ComboBoxStyle.DropDownList)
- Invalidate ();
+ Invalidate ();
if (listbox_ctrl != null)
listbox_ctrl.HighlightedIndex = value;
[Bindable(true)]
public object SelectedItem {
get { return selected_index == -1 ? null : Items [selected_index]; }
- set {
+ set {
object item = selected_index == -1 ? null : Items [selected_index];
if (item == value)
return;
-
SelectedIndex = Items.IndexOf (value);
}
}
public string SelectedText {
get {
if (dropdown_style == ComboBoxStyle.DropDownList)
- return "";
+ return string.Empty;
- return textbox_ctrl.SelectedText;
+ string retval = textbox_ctrl.SelectedText;
+
+#if ONLY_1_1
+ // On 1.1, the textbox will return null, combobox returns ""
+ if (retval == null && !textbox_ctrl.IsHandleCreated)
+ return string.Empty;
+#endif
+ return retval;
}
set {
if (dropdown_style == ComboBoxStyle.DropDownList)
return;
-
textbox_ctrl.SelectedText = value;
}
}
set {
if (dropdown_style == ComboBoxStyle.DropDownList)
return;
-
if (textbox_ctrl.SelectionLength == value)
return;
-
textbox_ctrl.SelectionLength = value;
}
}
public int SelectionStart {
get {
if (dropdown_style == ComboBoxStyle.DropDownList)
- return 0;
-
- return textbox_ctrl.SelectionStart;
+ return 0;
+ return textbox_ctrl.SelectionStart;
}
set {
if (dropdown_style == ComboBoxStyle.DropDownList)
return;
-
if (textbox_ctrl.SelectionStart == value)
- return;
-
+ return;
textbox_ctrl.SelectionStart = value;
}
}
[DefaultValue (false)]
public bool Sorted {
get { return sorted; }
-
- set {
+ set {
if (sorted == value)
return;
-
- sorted = value;
+ sorted = value;
SelectedIndex = -1;
if (sorted) {
Items.Sort ();
LayoutComboBox ();
}
- }
- }
+ }
+ }
[Bindable (true)]
[Localizable (true)]
return textbox_ctrl.Text;
}
}
-
+
if (SelectedItem != null)
return GetItemText (SelectedItem);
-
- return base.Text;
+
+ return base.Text;
}
- set {
+ set {
if (value == null) {
- SelectedIndex = -1;
+ if (SelectedIndex == -1) {
+ if (dropdown_style != ComboBoxStyle.DropDownList)
+ SetControlText ("");
+ } else {
+ SelectedIndex = -1;
+ }
return;
}
-
- int index = FindString (value);
-
+
+ // do nothing if value exactly matches text of selected item
+ if (SelectedItem != null && string.Compare (value, GetItemText (SelectedItem), false, CultureInfo.CurrentCulture) == 0)
+ return;
+
+ // find exact match using case-sensitive comparison, and if does
+ // not result in any match then use case-insensitive comparison
+ int index = FindStringExact (value, -1, false);
+ if (index == -1) {
+ index = FindStringExact (value, -1, true);
+ }
if (index != -1) {
SelectedIndex = index;
- return;
+ return;
}
-
+
if (dropdown_style != ComboBoxStyle.DropDownList)
textbox_ctrl.Text = GetItemText (value);
}
base.CreateHandle ();
}
#endif
+
protected override void Dispose (bool disposing)
- {
+ {
if (disposing) {
if (listbox_ctrl != null) {
listbox_ctrl.Dispose ();
Controls.RemoveImplicit (listbox_ctrl);
listbox_ctrl = null;
- }
+ }
if (textbox_ctrl != null) {
Controls.RemoveImplicit (textbox_ctrl);
textbox_ctrl.Dispose ();
textbox_ctrl = null;
- }
+ }
}
base.Dispose (disposing);
public int FindString (string s, int startIndex)
{
- if (Items.Count == 0)
- return -1; // No exception throwing if empty
+ if (s == null || Items.Count == 0)
+ return -1;
+#if NET_2_0
+ if (startIndex < -1 || startIndex >= Items.Count)
+#else
if (startIndex < -1 || startIndex >= Items.Count - 1)
- throw new ArgumentOutOfRangeException ("Index of out range");
+#endif
+ throw new ArgumentOutOfRangeException ("startIndex");
- startIndex++;
- for (int i = startIndex; i < Items.Count; i++) {
- if ((GetItemText (Items[i])).StartsWith (s))
+ int i = startIndex;
+#if NET_2_0
+ if (i == (Items.Count - 1))
+ i = -1;
+#endif
+ do {
+ i++;
+ if (string.Compare (s, 0, GetItemText (Items [i]), 0, s.Length, true) == 0)
return i;
- }
+ if (i == (Items.Count - 1))
+ i = -1;
+ } while (i != startIndex);
return -1;
}
public int FindStringExact (string s, int startIndex)
{
- if (Items.Count == 0)
- return -1; // No exception throwing if empty
+ return FindStringExact (s, startIndex, true);
+ }
+
+ private int FindStringExact (string s, int startIndex, bool ignoreCase)
+ {
+ if (s == null || Items.Count == 0)
+ return -1;
#if NET_2_0
if (startIndex < -1 || startIndex >= Items.Count)
#else
if (startIndex < -1 || startIndex >= Items.Count - 1)
#endif
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("startIndex");
- startIndex++;
- for (int i = startIndex; i < Items.Count; i++) {
- if ((GetItemText (Items[i])).Equals (s))
+ int i = startIndex;
+#if NET_2_0
+ if (i == (Items.Count - 1))
+ i = -1;
+#endif
+ do {
+ i++;
+ if (string.Compare (s, GetItemText (Items [i]), ignoreCase, CultureInfo.CurrentCulture) == 0)
return i;
- }
+ if (i == (Items.Count - 1))
+ i = -1;
+ } while (i != startIndex);
return -1;
}
public int GetItemHeight (int index)
- {
+ {
if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated) {
if (index < 0 || index >= Items.Count )
protected override bool IsInputKey (Keys keyData)
{
- switch (keyData) {
+ switch (keyData & ~Keys.Modifiers) {
case Keys.Up:
case Keys.Down:
case Keys.Left:
case Keys.Right:
case Keys.PageUp:
- case Keys.PageDown:
+ case Keys.PageDown:
+ case Keys.Home:
+ case Keys.End:
return true;
- default:
+ default:
return false;
}
}
protected override void OnBackColorChanged (EventArgs e)
{
base.OnBackColorChanged (e);
+
+ if (textbox_ctrl != null)
+ textbox_ctrl.BackColor = BackColor;
}
protected override void OnDataSourceChanged (EventArgs e)
{
base.OnDisplayMemberChanged (e);
- if (DataManager == null || !IsHandleCreated)
- return;
+ if (DataManager == null)
+ return;
+
+ if (selected_index != -1 && DropDownStyle != ComboBoxStyle.DropDownList)
+ SetControlText (GetItemText (Items [selected_index]));
+
+ if (!IsHandleCreated)
+ return;
- BindDataItems ();
SelectedIndex = DataManager.Position;
+ Invalidate ();
}
protected virtual void OnDrawItem (DrawItemEventArgs e)
ThemeEngine.Current.DrawComboBoxItem (this, e);
break;
}
- }
+ }
protected virtual void OnDropDown (EventArgs e)
{
eh (this, e);
}
#endif
+
protected virtual void OnDropDownStyleChanged (EventArgs e)
{
EventHandler eh = (EventHandler)(Events [DropDownStyleChangedEvent]);
textbox_ctrl.Font = Font;
if (!item_height_specified) {
- SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
+ SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
item_height = (int) sz.Height;
}
protected override void OnForeColorChanged (EventArgs e)
{
base.OnForeColorChanged (e);
+ if (textbox_ctrl != null)
+ textbox_ctrl.ForeColor = ForeColor;
}
- [EditorBrowsable(EditorBrowsableState.Advanced)]
+ [EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnGotFocus (EventArgs e)
{
if (dropdown_style == ComboBoxStyle.DropDownList) {
if (textbox_ctrl != null) {
textbox_ctrl.SetSelectable (false);
- textbox_ctrl.ActivateCaret (true);
textbox_ctrl.ShowSelection = true;
+ textbox_ctrl.ActivateCaret (true);
textbox_ctrl.SelectAll ();
}
base.OnGotFocus (e);
}
- [EditorBrowsable(EditorBrowsableState.Advanced)]
+ [EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnLostFocus (EventArgs e)
{
if (dropdown_style == ComboBoxStyle.DropDownList) {
textbox_ctrl.SetSelectable (true);
textbox_ctrl.ActivateCaret (false);
textbox_ctrl.ShowSelection = false;
+ textbox_ctrl.SelectionLength = 0;
}
base.OnLostFocus (e);
{
base.OnHandleCreated (e);
- if (listbox_ctrl != null) {
- Controls.AddImplicit (listbox_ctrl);
- listbox_ctrl.Visible = true;
- }
+ SetBounds (Left, Top, Width, PreferredHeight, BoundsSpecified.None);
if (textbox_ctrl != null)
Controls.AddImplicit (textbox_ctrl);
LayoutComboBox ();
+ UpdateComboBoxBounds ();
}
protected override void OnHandleDestroyed (EventArgs e)
protected override void OnKeyPress (KeyPressEventArgs e)
{
- // int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex);
- //if (index != -1)
- // SelectedIndex = index;
+ if (dropdown_style == ComboBoxStyle.DropDownList) {
+ int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex + 1);
+ if (index != -1) {
+ SelectedIndex = index;
+ if (DroppedDown) { //Scroll into view
+ if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
+ // Or, selecting an item earlier in the list.
+ if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+ }
+ }
+ }
base.OnKeyPress (e);
}
}
protected override void OnResize (EventArgs e)
- {
+ {
LayoutComboBox ();
if (listbox_ctrl != null)
listbox_ctrl.CalcListBoxArea ();
protected virtual void OnSelectedItemChanged (EventArgs e)
{
-
}
protected override void OnSelectedValueChanged (EventArgs e)
protected override void RefreshItem (int index)
{
if (index < 0 || index >= Items.Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("index");
if (draw_mode == DrawMode.OwnerDrawVariable)
item_heights.Remove (Items [index]);
}
#if NET_2_0
+ protected override void RefreshItems ()
+ {
+ for (int i = 0; i < Items.Count; i++) {
+ RefreshItem (i);
+ }
+ }
+
public override void ResetText ()
{
Text = String.Empty;
}
#endif
+#if NET_2_0
+ protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
+ {
+ base.ScaleControl (factor, specified);
+ }
+#endif
+
public void Select (int start, int length)
{
if (start < 0)
textbox_ctrl.ShowSelection = true;
textbox_ctrl.SelectAll ();
}
- }
+ }
protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
- {
+ {
if ((specified & BoundsSpecified.Height) != 0) {
requested_height = height;
Items.Clear ();
Items.AddRange (value);
} finally {
- EndUpdate ();
+ EndUpdate ();
}
}
if (textbox_ctrl != null)
XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam);
break;
- case Msg.WM_MOUSE_LEAVE:
+ case Msg.WM_MOUSELEAVE:
Point location = PointToClient (Control.MousePosition);
if (ClientRectangle.Contains (location))
return;
}
void LayoutComboBox ()
- {
+ {
int border = ThemeEngine.Current.Border3DSize.Width;
text_area = ClientRectangle;
button_area = Rectangle.Empty;
else {
button_area = text_area;
- button_area.X = text_area.Right - button_width - border;
- button_area.Y = text_area.Y + border;
+ button_area.X = text_area.Right - button_width - border;
+ button_area.Y = text_area.Y + border;
button_area.Width = button_width;
button_area.Height = text_area.Height - 2 * border;
#if NET_2_0
}
if (textbox_ctrl != null) {
- textbox_ctrl.Location = new Point (text_area.X + border, text_area.Y + border);
- textbox_ctrl.Width = text_area.Width - button_area.Width - border * 2;
- textbox_ctrl.Height = text_area.Height - border * 2;
+ int text_border = border + 1;
+ textbox_ctrl.Location = new Point (text_area.X + text_border, text_area.Y + text_border);
+ textbox_ctrl.Width = text_area.Width - button_area.Width - text_border * 2;
+ textbox_ctrl.Height = text_area.Height - text_border * 2;
}
if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) {
}
private void CreateComboListBox ()
- {
- listbox_ctrl = new ComboListBox (this);
+ {
+ listbox_ctrl = new ComboListBox (this);
listbox_ctrl.HighlightedIndex = SelectedIndex;
}
internal void Draw (Rectangle clip, Graphics dc)
- {
+ {
Theme theme = ThemeEngine.Current;
FlatStyle style = FlatStyle.Standard;
bool is_flat = false;
is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup;
#endif
+ if (!Enabled)
+ dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), bounds);
+
if (DropDownStyle == ComboBoxStyle.Simple)
dc.FillRectangle (theme.ResPool.GetSolidBrush (Parent.BackColor), ClientRectangle);
Rectangle item_rect = text_area;
item_rect.X += border;
item_rect.Y += border;
- item_rect.Width -= (button_area.Width + 2 * border);
- item_rect.Height -= 2 * border;
-
+ item_rect.Width -= (button_area.Width + 2 * border);
+ item_rect.Height -= 2 * border;
+
if (Focused) {
state = DrawItemState.Selected;
state |= DrawItemState.Focus;
}
- state |= DrawItemState.ComboBoxEdit;
+ state |= DrawItemState.ComboBoxEdit;
OnDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
- }
+ }
if (show_dropdown_button) {
- dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
+ ButtonState current_state;
+ if (is_enabled)
+ current_state = button_state;
+ else
+ current_state = ButtonState.Inactive;
+
+ if (is_flat || theme.ComboBoxNormalDropDownButtonHasTransparentBackground (this, current_state))
+ dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
- if (!is_enabled)
- button_state = ButtonState.Inactive;
-
if (is_flat) {
- theme.DrawFlatStyleComboButton (dc, button_area, button_state);
+ theme.DrawFlatStyleComboButton (dc, button_area, current_state);
} else {
- theme.CPDrawComboButton (dc, button_area, button_state);
+ theme.ComboBoxDrawNormalDropDownButton (this, dc, clip, button_area, current_state);
}
- }
+ }
+ }
+
+ internal bool DropDownButtonEntered {
+ get { return drop_down_button_entered; }
+ private set {
+ if (drop_down_button_entered == value)
+ return;
+ drop_down_button_entered = value;
+ if (ThemeEngine.Current.ComboBoxDropDownButtonHasHotElementStyle (this))
+ Invalidate (button_area);
+ }
}
internal void DropDownListBox ()
{
+ DropDownButtonEntered = false;
+
if (DropDownStyle == ComboBoxStyle.Simple)
- return;
+ return;
if (listbox_ctrl == null)
- CreateComboListBox ();
+ CreateComboListBox ();
listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
-
- if (listbox_ctrl.ShowWindow ())
- dropped_down = true;
-
- button_state = ButtonState.Pushed;
- if (dropdown_style == ComboBoxStyle.DropDownList)
- Invalidate (text_area);
+
+ FindMatchOrSetIndex(SelectedIndex);
+
+ if (listbox_ctrl.ShowWindow ())
+ dropped_down = true;
+
+ button_state = ButtonState.Pushed;
+ if (dropdown_style == ComboBoxStyle.DropDownList)
+ Invalidate (text_area);
}
internal void DropDownListBoxFinished ()
{
if (DropDownStyle == ComboBoxStyle.Simple)
- return;
+ return;
button_state = ButtonState.Normal;
Invalidate (button_area);
#if NET_2_0
OnDropDownClosed (EventArgs.Empty);
#endif
+ /*
+ * Apples X11 looses override-redirect when doing a Unmap/Map on a previously mapped window
+ * this causes the popup to appear under the main form. This is horrible but necessary
+ */
+
+ // If the user opens a new form in an event, it will close our dropdown,
+ // so we need a null check here
+ if (listbox_ctrl != null) {
+ listbox_ctrl.Dispose ();
+ listbox_ctrl = null;
+ }
}
private int FindStringCaseInsensitive (string search)
- {
+ {
if (search.Length == 0) {
return -1;
}
for (int i = 0; i < Items.Count; i++)
- {
+ {
if (String.Compare (GetItemText (Items[i]), 0, search, 0, search.Length, true) == 0)
return i;
}
return -1;
}
+ // Search in the list for the substring, starting the search at the list
+ // position specified, the search wraps thus covering all the list.
internal int FindStringCaseInsensitive (string search, int start_index)
{
if (search.Length == 0) {
return -1;
}
+ // Accept from first item to after last item. i.e. all cases of (SelectedIndex+1).
+ if (start_index < 0 || start_index > Items.Count)
+ throw new ArgumentOutOfRangeException("start_index");
for (int i = 0; i < Items.Count; i++) {
int index = (i + start_index) % Items.Count;
return -1;
}
+ internal override bool IsInputCharInternal (char charCode)
+ {
+ return true;
+ }
+
+ internal override ContextMenu ContextMenuInternal {
+ get {
+ return base.ContextMenuInternal;
+ }
+ set {
+ base.ContextMenuInternal = value;
+ if (textbox_ctrl != null) {
+ textbox_ctrl.ContextMenu = value;
+ }
+ }
+ }
+
+ internal void RestoreContextMenu ()
+ {
+ textbox_ctrl.RestoreContextMenu ();
+ }
+
private void OnKeyDownCB(object sender, KeyEventArgs e)
{
if (Items.Count == 0)
return;
+ int offset;
switch (e.KeyCode)
- {
+ {
case Keys.Up:
- SelectedIndex = Math.Max(SelectedIndex-1, 0);
- break;
+ FindMatchOrSetIndex(Math.Max(SelectedIndex - 1, 0));
+
+ if (DroppedDown)
+ if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+ break;
case Keys.Down:
- SelectedIndex = Math.Min(SelectedIndex+1, Items.Count-1);
+ if ((e.Modifiers & Keys.Alt) == Keys.Alt)
+ DropDownListBox ();
+ else
+ FindMatchOrSetIndex(Math.Min(SelectedIndex + 1, Items.Count - 1));
+
+ if (DroppedDown)
+ if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
break;
case Keys.PageUp:
- if (listbox_ctrl != null)
- SelectedIndex = Math.Max(SelectedIndex- (listbox_ctrl.page_size-1), 0);
- break;
+ offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1;
+ if (offset < 1)
+ offset = 1;
+
+ SelectedIndex = Math.Max (SelectedIndex - offset, 0);
+
+ if (DroppedDown)
+ if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+ break;
- case Keys.PageDown:
- if (listbox_ctrl != null)
- SelectedIndex = Math.Min(SelectedIndex+(listbox_ctrl.page_size-1), Items.Count-1);
+ case Keys.PageDown:
+ if (SelectedIndex == -1) {
+ SelectedIndex = 0;
+ if (dropdown_style != ComboBoxStyle.Simple)
+ return;
+ }
+
+ offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1;
+ if (offset < 1)
+ offset = 1;
+
+ SelectedIndex = Math.Min (SelectedIndex + offset, Items.Count - 1);
+
+ if (DroppedDown)
+ if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
+ break;
+
+ case Keys.Escape:
+ DropDownListBoxFinished ();
+ break;
+
+ case Keys.Home:
+ if (dropdown_style == ComboBoxStyle.DropDownList) {
+ SelectedIndex = 0;
+
+ if (DroppedDown)
+ if (SelectedIndex < listbox_ctrl.FirstVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ());
+ }
+
+ break;
+ case Keys.End:
+ if (dropdown_style == ComboBoxStyle.DropDownList) {
+ SelectedIndex = Items.Count - 1;
+
+ if (DroppedDown)
+ if (SelectedIndex >= listbox_ctrl.LastVisibleItem ())
+ listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1);
+ }
+
break;
-
default:
break;
}
}
+
+ // If no item is currently selected, and an item is found matching the text
+ // in the textbox, then selected that item. Otherwise the item at the given
+ // index is selected.
+ private void FindMatchOrSetIndex(int index)
+ {
+ int match = -1;
+ if (SelectedIndex == -1 && Text.Length != 0)
+ match = FindStringCaseInsensitive(Text);
+ if (match != -1)
+ SelectedIndex = match;
+ else
+ SelectedIndex = index;
+ }
void OnMouseDownCB (object sender, MouseEventArgs e)
- {
+ {
Rectangle area;
if (DropDownStyle == ComboBoxStyle.DropDownList)
area = ClientRectangle;
area = button_area;
if (area.Contains (e.X, e.Y)) {
- DropDownListBox ();
- Invalidate (button_area);
+ if (Items.Count > 0)
+ DropDownListBox ();
+ else {
+ button_state = ButtonState.Pushed;
+ OnDropDown (EventArgs.Empty);
+ }
+
+ Invalidate (button_area);
Update ();
- }
+ }
Capture = true;
- }
+ }
+
+ void OnMouseLeave (object sender, EventArgs e)
+ {
+ if (show_dropdown_button)
+ DropDownButtonEntered = false;
+ }
+
+ void OnMouseMoveCB (object sender, MouseEventArgs e)
+ {
+ if (show_dropdown_button && !dropped_down)
+ DropDownButtonEntered = button_area.Contains (e.Location);
- void OnMouseMoveCB (object sender, MouseEventArgs e)
- {
if (DropDownStyle == ComboBoxStyle.Simple)
return;
if (listbox_ctrl.ClientRectangle.Contains (location))
listbox_ctrl.Capture = true;
}
- }
+ }
- void OnMouseUpCB (object sender, MouseEventArgs e)
- {
+ void OnMouseUpCB (object sender, MouseEventArgs e)
+ {
Capture = false;
+
+ button_state = ButtonState.Normal;
+ Invalidate (button_area);
+
OnClick (EventArgs.Empty);
if (dropped_down)
listbox_ctrl.Capture = true;
- }
+ }
private void OnMouseWheelCB (object sender, MouseEventArgs me)
{
internal override void OnPaintInternal (PaintEventArgs pevent)
{
if (suspend_ctrlupdate)
- return;
-
- Draw (ClientRectangle, pevent.Graphics);
+ return;
+
+ Draw (ClientRectangle, pevent.Graphics);
}
private void OnTextBoxClick (object sender, EventArgs e)
{
if (process_textchanged_event == false)
return;
-
+
OnTextChanged (EventArgs.Empty);
int item = FindStringCaseInsensitive (textbox_ctrl.Text);
base.Text = textbox_ctrl.Text;
}
-
+
+ private void OnTextKeyPress (object sender, KeyPressEventArgs e)
+ {
+ selected_index = -1;
+ }
+
internal void SetControlText (string s)
- {
+ {
process_textchanged_event = false;
- textbox_ctrl.Text = s;
- process_textchanged_event = true;
- }
+ textbox_ctrl.Text = s;
+ textbox_ctrl.SelectAll ();
+ process_textchanged_event = true;
+ }
void UpdateComboBoxBounds ()
{
// Save the requested height since set bounds can destroy it
int save_height = requested_height;
- SetBounds (0, 0, 0, requested_height, BoundsSpecified.Height);
+ SetBounds (bounds.X, bounds.Y, bounds.Width, requested_height, BoundsSpecified.Height);
requested_height = save_height;
}
public virtual object this [int index] {
get {
if (index < 0 || index >= Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("index");
return object_items[index];
}
set {
if (index < 0 || index >= Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("index");
if (value == null)
throw new ArgumentNullException ("value");
owner.Refresh ();
}
- public bool Contains (object obj)
+ public bool Contains (object value)
{
- if (obj == null)
- throw new ArgumentNullException ("obj");
+ if (value == null)
+ throw new ArgumentNullException ("value");
- return object_items.Contains (obj);
+ return object_items.Contains (value);
}
- public void CopyTo (object[] dest, int arrayIndex)
+#if NET_2_0
+ public void CopyTo (object [] destination, int arrayIndex)
+ {
+ object_items.CopyTo (destination, arrayIndex);
+ }
+
+ void ICollection.CopyTo (Array destination, int index)
+ {
+ object_items.CopyTo (destination, index);
+ }
+#else
+ public void CopyTo (object [] dest, int arrayIndex)
{
object_items.CopyTo (dest, arrayIndex);
}
{
object_items.CopyTo (dest, index);
}
+#endif
public IEnumerator GetEnumerator ()
{
public void Insert (int index, object item)
{
if (index < 0 || index > Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("index");
if (item == null)
throw new ArgumentNullException ("item");
AddItem (item);
else
object_items.Insert (index, item);
-
+
owner.EndUpdate (); // Calls UpdatedItems
}
public void Remove (object value)
- {
+ {
if (value == null)
return;
if (IndexOf (value) == owner.SelectedIndex)
owner.SelectedIndex = -1;
- RemoveAt (IndexOf (value));
+ RemoveAt (IndexOf (value));
}
public void RemoveAt (int index)
{
if (index < 0 || index >= Count)
- throw new ArgumentOutOfRangeException ("Index of out range");
+ throw new ArgumentOutOfRangeException ("index");
if (index == owner.SelectedIndex)
owner.SelectedIndex = -1;
foreach (object o in object_items) {
if (String.Compare (item.ToString (), o.ToString ()) < 0) {
object_items.Insert (index, item);
+
+ // If we added the new item before the selectedindex
+ // bump the selectedindex by one, behavior differs if
+ // Handle has not been created.
+ if (index <= owner.selected_index && owner.IsHandleCreated)
+ owner.selected_index++;
+
return index;
}
index++;
{
foreach (object mi in items)
AddItem (mi);
-
+
owner.UpdatedItems ();
}
{
this.owner = owner;
ShowSelection = false;
+ HideSelection = false;
}
internal void SetSelectable (bool selectable)
protected override void OnLostFocus (EventArgs e)
{
owner.Select (false, true);
- }
+ }
+
+ public override bool Focused {
+ get {
+ return owner.Focused;
+ }
+ }
+
+ internal override bool ActivateOnShow { get { return false; } }
}
internal class ComboListBox : Control
{
- private ComboBox owner;
+ private ComboBox owner;
private VScrollBarLB vscrollbar_ctrl;
private int top_item; /* First item that we show the in the current page */
private int last_item; /* Last visible item */
class VScrollBarLB : VScrollBar
{
public VScrollBarLB ()
- {
+ {
}
internal override bool InternalCapture {
e = TranslateEvent (e);
OnMouseDown (e);
- }
+ }
public void FireMouseUp (MouseEventArgs e)
{
e = TranslateEvent (e);
OnMouseMove (e);
- }
+ }
MouseEventArgs TranslateEvent (MouseEventArgs e)
{
Point loc = PointToClient (Control.MousePosition);
- return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta);
+ return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta);
}
}
public ComboListBox (ComboBox owner)
- {
- this.owner = owner;
+ {
+ this.owner = owner;
top_item = 0;
last_item = 0;
page_size = 0;
SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
this.is_visible = false;
- Hwnd.ObjectFromHandle (this.Handle).no_activate = true;
if (owner.DropDownStyle == ComboBoxStyle.Simple)
InternalBorderStyle = BorderStyle.Fixed3D;
protected override CreateParams CreateParams
{
get {
- CreateParams cp = base.CreateParams;
+ CreateParams cp = base.CreateParams;
if (owner == null || owner.DropDownStyle == ComboBoxStyle.Simple)
return cp;
- cp.Style ^= (int) WindowStyles.WS_CHILD;
- cp.Style |= (int) WindowStyles.WS_POPUP;
+ cp.Style ^= (int)WindowStyles.WS_CHILD;
+ cp.Style ^= (int)WindowStyles.WS_VISIBLE;
+ cp.Style |= (int)WindowStyles.WS_POPUP;
cp.ExStyle |= (int) WindowExStyles.WS_EX_TOOLWINDOW | (int) WindowExStyles.WS_EX_TOPMOST;
return cp;
}
}
- protected override void Select (bool directed, bool forward)
- {
- // Do nothing, we never want to be selected
- }
-
internal override bool InternalCapture {
get {
return Capture;
}
}
- int BorderWidth {
- get {
- switch (border_style) {
- case BorderStyle.Fixed3D:
- return ThemeEngine.Current.Border3DSize.Width;
- default:
- return ThemeEngine.Current.BorderSize.Width;
- }
- }
- }
+ internal override bool ActivateOnShow { get { return false; } }
+ #region Private Methods
- #region Private Methods
// Calcs the listbox area
internal void CalcListBoxArea ()
- {
+ {
int width, height;
bool show_scrollbar = false;
-
+
if (owner.DropDownStyle == ComboBoxStyle.Simple) {
Rectangle area = owner.listbox_area;
width = area.Width;
height = area.Height;
+
+ // No calculation needed
+ if (height <= 0 || width <= 0)
+ return;
}
else { // DropDown or DropDownList
width = owner.DropDownWidth;
- int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;
+ int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;
- if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
+ if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
height = 0;
for (int i = 0; i < count; i++) {
height += owner.GetItemHeight (i);
}
}
- page_size = height / owner.ItemHeight;
+ page_size = Math.Max (height / owner.ItemHeight, 1);
+
+ ComboBoxStyle dropdown_style = owner.DropDownStyle;
+ if ((dropdown_style != ComboBoxStyle.Simple && owner.Items.Count <= owner.MaxDropDownItems)
+ || (dropdown_style == ComboBoxStyle.Simple && owner.Items.Count * owner.ItemHeight < height)) {
- if (owner.Items.Count <= owner.MaxDropDownItems) {
if (vscrollbar_ctrl != null)
vscrollbar_ctrl.Visible = false;
- } else {
+ if (dropdown_style != ComboBoxStyle.Simple)
+ height = owner.ItemHeight * owner.items.Count;
+ } else {
/* Need vertical scrollbar */
if (vscrollbar_ctrl == null) {
vscrollbar_ctrl = new VScrollBarLB ();
Controls.AddImplicit (vscrollbar_ctrl);
}
- vscrollbar_ctrl.Height = height - 2 * BorderWidth;
-
- vscrollbar_ctrl.Location = new Point (width - vscrollbar_ctrl.Width - BorderWidth - 1, 0);
+ vscrollbar_ctrl.Dock = DockStyle.Right;
- vscrollbar_ctrl.Maximum = owner.Items.Count - 2;
- int large = (owner.DropDownStyle == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
- if (large < 0)
- large = 0;
+ vscrollbar_ctrl.Maximum = owner.Items.Count - 1;
+#if NET_2_0
+ int large = page_size;
+#else
+ int large = (dropdown_style == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
+#endif
+ if (large < 1)
+ large = 1;
vscrollbar_ctrl.LargeChange = large;
show_scrollbar = vscrollbar_ctrl.Visible = true;
Size = new Size (width, height);
textarea_drawable = ClientRectangle;
textarea_drawable.Width = width;
- textarea_drawable.Height = height;
+ textarea_drawable.Height = height;
if (vscrollbar_ctrl != null && show_scrollbar)
textarea_drawable.Width -= vscrollbar_ctrl.Width;
last_item = LastVisibleItem ();
- }
+ }
private void Draw (Rectangle clip, Graphics dc)
- {
+ {
dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (owner.BackColor), clip);
if (owner.Items.Count > 0) {
if (owner.DropDownStyle == ComboBoxStyle.DropDownList) {
state |= DrawItemState.Focus;
- }
+ }
}
-
+
owner.OnDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
i, state, owner.ForeColor, owner.BackColor));
}
if (highlighted_index != -1 && highlighted_index < this.owner.Items.Count)
Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
highlighted_index = value;
- if (highlighted_index != -1)
+ if (highlighted_index != -1)
Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
}
}
private int IndexFromPointDisplayRectangle (int x, int y)
{
- for (int i = top_item; i <= last_item; i++) {
+ for (int i = top_item; i <= last_item; i++) {
if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true)
return i;
}
Invalidate (GetItemDisplayRectangle (index, top_item));
}
- private int LastVisibleItem ()
+ public int LastVisibleItem ()
{
Rectangle item_rect;
int top_y = textarea_drawable.Y + textarea_drawable.Height;
- int i = 0;
+ int i = 0;
for (i = top_item; i < owner.Items.Count; i++) {
- item_rect = GetItemDisplayRectangle (i, top_item);
+ item_rect = GetItemDisplayRectangle (i, top_item);
if (item_rect.Y + item_rect.Height > top_y) {
return i;
}
top_item = item;
UpdateLastVisibleItem ();
Invalidate ();
- }
+ }
+ public int FirstVisibleItem ()
+ {
+ return top_item;
+ }
+
bool scrollbar_grabbed = false;
bool InScrollBar {
}
protected override void OnMouseMove (MouseEventArgs e)
- {
+ {
if (owner.DropDownStyle == ComboBoxStyle.Simple)
return;
Point pt = PointToClient (Control.MousePosition);
int index = IndexFromPointDisplayRectangle (pt.X, pt.Y);
- if (index != -1)
+ if (index != -1)
HighlightedIndex = index;
}
protected override void OnMouseUp (MouseEventArgs e)
{
- int index = IndexFromPointDisplayRectangle (e.X, e.Y);
+ int index = IndexFromPointDisplayRectangle (e.X, e.Y);
if (scrollbar_grabbed) {
vscrollbar_ctrl.FireMouseUp (e);
return;
}
- if (index == -1) {
- HideWindow ();
+ if (index == -1) {
+ HideWindow ();
return;
}
}
internal override void OnPaintInternal (PaintEventArgs pevent)
- {
+ {
Draw (pevent.ClipRectangle,pevent.Graphics);
}
HighlightedIndex = owner.SelectedIndex;
- CalcListBoxArea ();
+ CalcListBoxArea ();
Show ();
Refresh ();
if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible)
return;
- int max = owner.Items.Count - page_size;
+ int max = vscrollbar_ctrl.Maximum - page_size + 1;
int val = vscrollbar_ctrl.Value + delta;
if (val > max)
// Value Changed
private void VerticalScrollEvent (object sender, EventArgs e)
- {
+ {
if (top_item == vscrollbar_ctrl.Value)
return;
top_item = vscrollbar_ctrl.Value;
UpdateLastVisibleItem ();
Invalidate ();
- }
+ }
protected override void WndProc(ref Message m) {
if (m.Msg == (int)Msg.WM_SETFOCUS) {
- if (m.WParam != IntPtr.Zero) {
- XplatUI.SetFocus(m.WParam);
- }
+ owner.Select (false, true);
}
base.WndProc (ref m);
}
}
}
}
-
-