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
MouseUp += new MouseEventHandler (OnMouseUpCB);
MouseMove += new MouseEventHandler (OnMouseMoveCB);
MouseWheel += new MouseEventHandler (OnMouseWheelCB);
+ MouseLeave += new EventHandler (OnMouseLeave);
KeyDown +=new KeyEventHandler(OnKeyDownCB);
}
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;
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;
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)
{
base.OnDisplayMemberChanged (e);
- if (DataManager == null || !IsHandleCreated)
+ 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)
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);
}
#endif
#if NET_2_0
- private float current_factor_width = 1f;
-
- // WTF? WTF? WTF????
- // I am sure this is tied to something I missed that makes this make sense.
- // Every time you double the size of the control, subtract 4 pixels from it
protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
{
- // Never change the ComboBox's height
- specified &= ~BoundsSpecified.Height;
-
- int width = ClientSize.Width;
-
- // Go back to the original (un-4-subtracted) size
- if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width)
- width += (int)(((current_factor_width) - 1f) * 4.0f);
-
- Rectangle new_bounds = GetScaledBounds (new Rectangle (Location, new Size (width, ClientSize.Height)), factor, specified);
-
- // Subtract 4 for every time the control is 'doubled'
- if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width) {
- new_bounds.Width += (int)(((factor.Width * current_factor_width) - 1f) * -4.0f);
- current_factor_width *= factor.Width;
- }
-
- SetBounds (new_bounds.X, new_bounds.Y, new_bounds.Width, new_bounds.Height, specified);
+ base.ScaleControl (factor, specified);
}
#endif
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);
}
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_flat) {
theme.DrawFlatStyleComboButton (dc, button_area, current_state);
} else {
- theme.CPDrawComboButton (dc, button_area, current_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;
listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
+ FindMatchOrSetIndex(SelectedIndex);
+
if (listbox_ctrl.ShowWindow ())
dropped_down = true;
#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)
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;
}
}
+ 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);
+ 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);
+ 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);
+ 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)
{
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);
+
if (DropDownStyle == ComboBoxStyle.Simple)
return;
{
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;
+ textbox_ctrl.SelectAll ();
process_textchanged_event = true;
}
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 ()
{
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++;
{
this.owner = owner;
ShowSelection = false;
+ HideSelection = false;
}
internal void SetSelectable (bool selectable)
}
}
- protected override void Select (bool directed, bool forward)
- {
- // Do nothing, we never want to be selected
- }
-
internal override bool InternalCapture {
get {
return Capture;
{
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
}
}
- 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;
- height = owner.ItemHeight * owner.items.Count;
+ if (dropdown_style != ComboBoxStyle.Simple)
+ height = owner.ItemHeight * owner.items.Count;
} else {
/* Need vertical scrollbar */
if (vscrollbar_ctrl == null) {
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;
Invalidate (GetItemDisplayRectangle (index, top_item));
}
- private int LastVisibleItem ()
+ public int LastVisibleItem ()
{
Rectangle item_rect;
int top_y = textarea_drawable.Y + textarea_drawable.Height;
Invalidate ();
}
+ public int FirstVisibleItem ()
+ {
+ return top_item;
+ }
+
bool scrollbar_grabbed = false;
bool InScrollBar {
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)
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);
}