revert r69151
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms / ListBox.cs
blob52b4f2b50ded8cdd0bf551b06e57dbd498d6086f
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2006 Novell, Inc.
22 // Authors:
23 // Jordi Mas i Hernandez, jordi@ximian.com
24 // Mike Kestner <mkestner@novell.com>
27 // COMPLETE
29 using System;
30 using System.Drawing;
31 using System.Collections;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.ComponentModel.Design.Serialization;
35 using System.Reflection;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms
40 [DefaultProperty("Items")]
41 [DefaultEvent("SelectedIndexChanged")]
42 [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43 public class ListBox : ListControl
45 public const int DefaultItemHeight = 13;
46 public const int NoMatches = -1;
48 internal enum ItemNavigation
50 First,
51 Last,
52 Next,
53 Previous,
54 NextPage,
55 PreviousPage,
56 PreviousColumn,
57 NextColumn
60 Hashtable item_heights;
61 private int item_height = -1;
62 private int column_width = 0;
63 private int requested_height = -1;
64 private DrawMode draw_mode = DrawMode.Normal;
65 private int horizontal_extent = 0;
66 private bool horizontal_scrollbar = false;
67 private bool integral_height = true;
68 private bool multicolumn = false;
69 private bool scroll_always_visible = false;
70 private int selected_index = -1;
71 private SelectedIndexCollection selected_indices;
72 private SelectedObjectCollection selected_items;
73 private ArrayList selection = new ArrayList ();
74 private SelectionMode selection_mode = SelectionMode.One;
75 private bool sorted = false;
76 private bool use_tabstops = true;
77 private int column_width_internal = 120;
78 private ImplicitVScrollBar vscrollbar;
79 private ImplicitHScrollBar hscrollbar;
80 private int hbar_offset;
81 private bool suspend_layout;
82 private bool ctrl_pressed = false;
83 private bool shift_pressed = false;
84 private bool explicit_item_height = false;
85 private int top_index = 0;
86 private int last_visible_index = 0;
87 private Rectangle items_area;
88 private int focused_item = -1;
89 private ObjectCollection items;
91 public ListBox ()
93 border_style = BorderStyle.Fixed3D;
94 BackColor = ThemeEngine.Current.ColorWindow;
96 items = CreateItemCollection ();
97 selected_indices = new SelectedIndexCollection (this);
98 selected_items = new SelectedObjectCollection (this);
100 /* Vertical scrollbar */
101 vscrollbar = new ImplicitVScrollBar ();
102 vscrollbar.Minimum = 0;
103 vscrollbar.SmallChange = 1;
104 vscrollbar.LargeChange = 1;
105 vscrollbar.Maximum = 0;
106 vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
107 vscrollbar.Visible = false;
109 /* Horizontal scrollbar */
110 hscrollbar = new ImplicitHScrollBar ();
111 hscrollbar.Minimum = 0;
112 hscrollbar.SmallChange = 1;
113 hscrollbar.LargeChange = 1;
114 hscrollbar.Maximum = 0;
115 hscrollbar.Visible = false;
116 hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
118 /* Events */
119 MouseDown += new MouseEventHandler (OnMouseDownLB);
120 MouseMove += new MouseEventHandler (OnMouseMoveLB);
121 MouseUp += new MouseEventHandler (OnMouseUpLB);
122 MouseWheel += new MouseEventHandler (OnMouseWheelLB);
123 KeyDown += new KeyEventHandler (OnKeyDownLB);
124 KeyUp += new KeyEventHandler (OnKeyUpLB);
125 GotFocus += new EventHandler (OnGotFocus);
126 LostFocus += new EventHandler (OnLostFocus);
128 SetStyle (ControlStyles.UserPaint, false);
131 #region Events
132 static object DrawItemEvent = new object ();
133 static object MeasureItemEvent = new object ();
134 static object SelectedIndexChangedEvent = new object ();
136 [Browsable (false)]
137 [EditorBrowsable (EditorBrowsableState.Never)]
138 public new event EventHandler BackgroundImageChanged {
139 add { base.BackgroundImageChanged += value; }
140 remove { base.BackgroundImageChanged -= value; }
143 [Browsable (false)]
144 [EditorBrowsable (EditorBrowsableState.Advanced)]
145 public new event EventHandler Click {
146 add { base.Click += value; }
147 remove { base.Click -= value; }
150 public event DrawItemEventHandler DrawItem {
151 add { Events.AddHandler (DrawItemEvent, value); }
152 remove { Events.RemoveHandler (DrawItemEvent, value); }
155 public event MeasureItemEventHandler MeasureItem {
156 add { Events.AddHandler (MeasureItemEvent, value); }
157 remove { Events.RemoveHandler (MeasureItemEvent, value); }
160 [Browsable (false)]
161 [EditorBrowsable (EditorBrowsableState.Never)]
162 public new event PaintEventHandler Paint {
163 add { base.Paint += value; }
164 remove { base.Paint -= value; }
167 public event EventHandler SelectedIndexChanged {
168 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
169 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
172 [Browsable (false)]
173 [EditorBrowsable (EditorBrowsableState.Advanced)]
174 public new event EventHandler TextChanged {
175 add { base.TextChanged += value; }
176 remove { base.TextChanged -= value; }
178 #endregion // Events
180 #region Public Properties
181 public override Color BackColor {
182 get { return base.BackColor; }
183 set {
184 if (base.BackColor == value)
185 return;
187 base.BackColor = value;
188 base.Refresh (); // Careful. Calling the base method is not the same that calling
189 } // the overriden one that refresh also all the items
192 [Browsable (false)]
193 [EditorBrowsable (EditorBrowsableState.Never)]
194 public override Image BackgroundImage {
195 get { return base.BackgroundImage; }
196 set {
197 base.BackgroundImage = value;
198 base.Refresh ();
202 [DefaultValue (BorderStyle.Fixed3D)]
203 [DispId(-504)]
204 public BorderStyle BorderStyle {
205 get { return InternalBorderStyle; }
206 set {
207 InternalBorderStyle = value;
208 UpdateListBoxBounds ();
212 [DefaultValue (0)]
213 [Localizable (true)]
214 public int ColumnWidth {
215 get { return column_width; }
216 set {
217 if (value < 0)
218 throw new ArgumentException ("A value less than zero is assigned to the property.");
220 column_width = value;
222 if (value == 0)
223 ColumnWidthInternal = 120;
224 else
225 ColumnWidthInternal = value;
227 base.Refresh ();
231 protected override CreateParams CreateParams {
232 get { return base.CreateParams;}
235 protected override Size DefaultSize {
236 get { return new Size (120, 96); }
239 [RefreshProperties(RefreshProperties.Repaint)]
240 [DefaultValue (DrawMode.Normal)]
241 public virtual DrawMode DrawMode {
242 get { return draw_mode; }
244 set {
245 if (!Enum.IsDefined (typeof (DrawMode), value))
246 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
248 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
249 throw new ArgumentException ("Cannot have variable height and multicolumn");
251 if (draw_mode == value)
252 return;
254 draw_mode = value;
256 if (draw_mode == DrawMode.OwnerDrawVariable)
257 item_heights = new Hashtable ();
258 else
259 item_heights = null;
261 base.Refresh ();
265 public override Color ForeColor {
266 get { return base.ForeColor; }
267 set {
269 if (base.ForeColor == value)
270 return;
272 base.ForeColor = value;
273 base.Refresh ();
277 [DefaultValue (0)]
278 [Localizable (true)]
279 public int HorizontalExtent {
280 get { return horizontal_extent; }
281 set {
282 if (horizontal_extent == value)
283 return;
285 horizontal_extent = value;
286 base.Refresh ();
290 [DefaultValue (false)]
291 [Localizable (true)]
292 public bool HorizontalScrollbar {
293 get { return horizontal_scrollbar; }
294 set {
295 if (horizontal_scrollbar == value)
296 return;
298 horizontal_scrollbar = value;
299 UpdateScrollBars ();
300 base.Refresh ();
304 [DefaultValue (true)]
305 [Localizable (true)]
306 [RefreshProperties(RefreshProperties.Repaint)]
307 public bool IntegralHeight {
308 get { return integral_height; }
309 set {
310 if (integral_height == value)
311 return;
313 integral_height = value;
314 UpdateListBoxBounds ();
318 [DefaultValue (13)]
319 [Localizable (true)]
320 [RefreshProperties(RefreshProperties.Repaint)]
321 public virtual int ItemHeight {
322 get {
323 if (item_height == -1) {
324 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
325 item_height = (int) sz.Height;
327 return item_height;
329 set {
330 if (value > 255)
331 throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
333 explicit_item_height = true;
334 if (item_height == value)
335 return;
337 item_height = value;
338 if (IntegralHeight)
339 UpdateListBoxBounds ();
340 LayoutListBox ();
344 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
345 [Localizable (true)]
346 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
347 public ObjectCollection Items {
348 get { return items; }
351 [DefaultValue (false)]
352 public bool MultiColumn {
353 get { return multicolumn; }
354 set {
355 if (multicolumn == value)
356 return;
358 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
359 throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
361 multicolumn = value;
362 LayoutListBox ();
366 [Browsable (false)]
367 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
368 [EditorBrowsable (EditorBrowsableState.Advanced)]
369 public int PreferredHeight {
370 get {
371 int itemsHeight = 0;
372 if (draw_mode == DrawMode.Normal)
373 itemsHeight = FontHeight * items.Count;
374 else if (draw_mode == DrawMode.OwnerDrawFixed)
375 itemsHeight = ItemHeight * items.Count;
376 else if (draw_mode == DrawMode.OwnerDrawVariable) {
377 for (int i = 0; i < items.Count; i++)
378 itemsHeight += (int) item_heights [Items [i]];
381 return itemsHeight;
385 public override RightToLeft RightToLeft {
386 get { return base.RightToLeft; }
387 set {
388 base.RightToLeft = value;
389 if (base.RightToLeft == RightToLeft.Yes)
390 StringFormat.Alignment = StringAlignment.Far;
391 else
392 StringFormat.Alignment = StringAlignment.Near;
393 base.Refresh ();
397 // Only affects the Vertical ScrollBar
398 [DefaultValue (false)]
399 [Localizable (true)]
400 public bool ScrollAlwaysVisible {
401 get { return scroll_always_visible; }
402 set {
403 if (scroll_always_visible == value)
404 return;
406 scroll_always_visible = value;
407 UpdateScrollBars ();
411 [Bindable(true)]
412 [Browsable (false)]
413 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
414 public override int SelectedIndex {
415 get { return selected_index;}
416 set {
417 if (value < -1 || value >= Items.Count)
418 throw new ArgumentOutOfRangeException ("Index of out range");
420 if (SelectionMode == SelectionMode.None)
421 throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
423 if (selected_index == value)
424 return;
426 if (value == -1)
427 ClearSelected ();
428 else if (SelectionMode == SelectionMode.One)
429 UnSelectItem (selected_index, true);
431 if (value < top_index)
433 top_index = value;
434 UpdateTopItem ();
435 } else {
436 int rows = items_area.Height / ItemHeight;
437 if (value >= (top_index + rows))
439 top_index = value - rows + 1;
440 UpdateTopItem ();
443 SelectItem (value);
444 selected_index = value;
445 FocusedItem = value;
446 OnSelectedIndexChanged (new EventArgs ());
447 OnSelectedValueChanged (new EventArgs ());
451 [Browsable (false)]
452 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
453 public SelectedIndexCollection SelectedIndices {
454 get { return selected_indices; }
457 [Bindable(true)]
458 [Browsable (false)]
459 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
460 public object SelectedItem {
461 get {
462 if (SelectedItems.Count > 0)
463 return SelectedItems[0];
464 else
465 return null;
467 set {
468 if (value != null && !Items.Contains (value))
469 return; // FIXME: this is probably an exception
471 SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
475 [Browsable (false)]
476 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
477 public SelectedObjectCollection SelectedItems {
478 get {return selected_items;}
481 [DefaultValue (SelectionMode.One)]
482 public virtual SelectionMode SelectionMode {
483 get { return selection_mode; }
484 set {
485 if (!Enum.IsDefined (typeof (SelectionMode), value))
486 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
488 if (selection_mode == value)
489 return;
491 selection_mode = value;
493 switch (selection_mode) {
494 case SelectionMode.None:
495 ClearSelected ();
496 break;
498 case SelectionMode.One:
499 while (SelectedIndices.Count > 1)
500 UnSelectItem (SelectedIndices [SelectedIndices.Count - 1], true);
501 break;
503 default:
504 break;
509 [DefaultValue (false)]
510 public bool Sorted {
511 get { return sorted; }
513 set {
514 if (sorted == value)
515 return;
517 sorted = value;
518 if (sorted)
519 Sort ();
523 [Bindable (false)]
524 [Browsable (false)]
525 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
526 [EditorBrowsable (EditorBrowsableState.Advanced)]
527 public override string Text {
528 get {
529 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
530 return GetItemText (SelectedItem);
532 return base.Text;
534 set {
536 base.Text = value;
538 if (SelectionMode == SelectionMode.None)
539 return;
541 int index;
543 index = FindStringExact (value);
545 if (index == -1)
546 return;
548 SelectedIndex = index;
552 [Browsable (false)]
553 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
554 public int TopIndex {
555 get { return top_index; }
556 set {
557 if (value == top_index)
558 return;
560 if (value < 0 || value >= Items.Count)
561 return;
563 top_index = value;
564 UpdateTopItem ();
565 base.Refresh ();
569 [DefaultValue (true)]
570 public bool UseTabStops {
571 get { return use_tabstops; }
573 set {
574 if (use_tabstops == value)
575 return;
577 use_tabstops = value;
578 if (use_tabstops)
579 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
580 else
581 StringFormat.SetTabStops (0, new float [0]);
582 base.Refresh ();
586 #endregion Public Properties
588 #region Private Properties
590 private int ColumnWidthInternal {
591 get { return column_width_internal; }
592 set { column_width_internal = value; }
595 private int row_count = 1;
596 private int RowCount {
597 get {
598 return MultiColumn ? row_count : Items.Count;
602 #endregion Private Properties
604 #region Public Methods
605 protected virtual void AddItemsCore (object[] value)
607 Items.AddRange (value);
610 public void BeginUpdate ()
612 suspend_layout = true;
615 public void ClearSelected ()
617 foreach (int i in selected_indices) {
618 UnSelectItem (i, false);
621 selection.Clear ();
624 protected virtual ObjectCollection CreateItemCollection ()
626 return new ObjectCollection (this);
629 public void EndUpdate ()
631 suspend_layout = false;
632 LayoutListBox ();
633 base.Refresh ();
636 public int FindString (String s)
638 return FindString (s, -1);
641 public int FindString (string s, int startIndex)
643 if (Items.Count == 0)
644 return -1; // No exception throwing if empty
646 if (startIndex < -1 || startIndex >= Items.Count - 1)
647 throw new ArgumentOutOfRangeException ("Index of out range");
649 startIndex++;
650 for (int i = startIndex; i < Items.Count; i++) {
651 if ((GetItemText (Items[i])).StartsWith (s))
652 return i;
655 return NoMatches;
658 public int FindStringExact (string s)
660 return FindStringExact (s, -1);
663 public int FindStringExact (string s, int startIndex)
665 if (Items.Count == 0)
666 return -1; // No exception throwing if empty
668 if (startIndex < -1 || startIndex >= Items.Count - 1)
669 throw new ArgumentOutOfRangeException ("Index of out range");
671 startIndex++;
672 for (int i = startIndex; i < Items.Count; i++) {
673 if ((GetItemText (Items[i])).Equals (s))
674 return i;
677 return NoMatches;
680 public int GetItemHeight (int index)
682 if (index < 0 || index >= Items.Count)
683 throw new ArgumentOutOfRangeException ("Index of out range");
685 if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
687 object o = Items [index];
688 if (item_heights.Contains (o))
689 return (int) item_heights [o];
691 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
692 OnMeasureItem (args);
693 item_heights [o] = args.ItemHeight;
694 return args.ItemHeight;
697 return ItemHeight;
700 public Rectangle GetItemRectangle (int index)
702 if (index < 0 || index >= Items.Count)
703 throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
705 Rectangle rect = new Rectangle ();
707 if (MultiColumn) {
708 int col = index / RowCount;
709 rect.Y = ((index - top_index) % RowCount) * ItemHeight;
710 rect.X = col * ColumnWidthInternal;
711 rect.Height = ItemHeight;
712 rect.Width = ColumnWidthInternal;
713 } else {
714 rect.X = 0;
715 rect.Height = GetItemHeight (index);
716 rect.Width = items_area.Width;
718 if (DrawMode == DrawMode.OwnerDrawVariable) {
719 rect.Y = 0;
720 if (index >= top_index) {
721 for (int i = top_index; i < index; i++) {
722 rect.Y += GetItemHeight (i);
724 } else {
725 for (int i = index; i < top_index; i++) {
726 rect.Y -= GetItemHeight (i);
729 } else {
730 rect.Y = ItemHeight * (index - top_index);
734 return rect;
737 public bool GetSelected (int index)
739 if (index < 0 || index >= Items.Count)
740 throw new ArgumentOutOfRangeException ("Index of out range");
742 return SelectedIndices.Contains (index);
745 public int IndexFromPoint (Point p)
747 return IndexFromPoint (p.X, p.Y);
750 // Only returns visible points
751 public int IndexFromPoint (int x, int y)
754 if (Items.Count == 0) {
755 return -1;
758 for (int i = top_index; i <= last_visible_index; i++) {
759 if (GetItemRectangle (i).Contains (x,y) == true)
760 return i;
763 return -1;
766 protected override void OnChangeUICues (UICuesEventArgs e)
768 base.OnChangeUICues (e);
771 protected override void OnDataSourceChanged (EventArgs e)
773 base.OnDataSourceChanged (e);
774 BindDataItems ();
776 if (DataSource == null || DataManager == null) {
777 SelectedIndex = -1;
779 else {
780 SelectedIndex = DataManager.Position;
784 protected override void OnDisplayMemberChanged (EventArgs e)
786 base.OnDisplayMemberChanged (e);
788 if (DataManager == null || !IsHandleCreated)
789 return;
791 BindDataItems ();
792 base.Refresh ();
795 protected virtual void OnDrawItem (DrawItemEventArgs e)
797 switch (DrawMode) {
798 case DrawMode.OwnerDrawFixed:
799 case DrawMode.OwnerDrawVariable:
800 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
801 if (eh != null)
802 eh (this, e);
804 break;
806 default:
807 ThemeEngine.Current.DrawListBoxItem (this, e);
808 break;
812 protected override void OnFontChanged (EventArgs e)
814 base.OnFontChanged (e);
816 if (use_tabstops)
817 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
819 if (explicit_item_height) {
820 base.Refresh ();
821 } else {
822 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
823 item_height = (int) sz.Height;
824 if (IntegralHeight)
825 UpdateListBoxBounds ();
826 LayoutListBox ();
830 protected override void OnHandleCreated (EventArgs e)
832 base.OnHandleCreated (e);
834 SuspendLayout ();
835 Controls.AddImplicit (vscrollbar);
836 Controls.AddImplicit (hscrollbar);
837 ResumeLayout ();
838 LayoutListBox ();
841 protected override void OnHandleDestroyed (EventArgs e)
843 base.OnHandleDestroyed (e);
846 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
848 if (draw_mode != DrawMode.OwnerDrawVariable)
849 return;
851 MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
852 if (eh != null)
853 eh (this, e);
856 protected override void OnParentChanged (EventArgs e)
858 base.OnParentChanged (e);
861 protected override void OnResize (EventArgs e)
863 base.OnResize (e);
864 if (canvas_size.IsEmpty || MultiColumn)
865 LayoutListBox ();
868 protected override void OnSelectedIndexChanged (EventArgs e)
870 base.OnSelectedIndexChanged (e);
872 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
873 if (eh != null)
874 eh (this, e);
877 protected override void OnSelectedValueChanged (EventArgs e)
879 base.OnSelectedValueChanged (e);
882 public override void Refresh ()
884 if (draw_mode == DrawMode.OwnerDrawVariable)
885 item_heights.Clear ();
887 base.Refresh ();
890 protected override void RefreshItem (int index)
892 if (index < 0 || index >= Items.Count)
893 throw new ArgumentOutOfRangeException ("Index of out range");
895 if (draw_mode == DrawMode.OwnerDrawVariable)
896 item_heights.Remove (Items [index]);
899 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
901 if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
902 requested_height = height;
904 if (IntegralHeight) {
905 int border;
906 switch (border_style) {
907 case BorderStyle.Fixed3D:
908 border = ThemeEngine.Current.Border3DSize.Height;
909 break;
910 case BorderStyle.FixedSingle:
911 border = ThemeEngine.Current.BorderSize.Height;
912 break;
913 case BorderStyle.None:
914 default:
915 border = 0;
916 break;
918 height -= (2 * border);
919 height -= height % ItemHeight;
920 height += (2 * border);
923 base.SetBoundsCore (x, y, width, height, specified);
924 UpdateScrollBars ();
927 protected override void SetItemCore (int index, object value)
929 if (index < 0 || index >= Items.Count)
930 return;
932 Items[index] = value;
935 protected override void SetItemsCore (IList value)
937 BeginUpdate ();
938 try {
939 Items.Clear ();
940 Items.AddRange (value);
941 } finally {
942 EndUpdate ();
946 public void SetSelected (int index, bool value)
948 if (index < 0 || index >= Items.Count)
949 throw new ArgumentOutOfRangeException ("Index of out range");
951 if (SelectionMode == SelectionMode.None)
952 throw new InvalidOperationException ();
954 if (value)
955 SelectItem (index);
956 else
957 UnSelectItem (index, true);
960 protected virtual void Sort ()
962 if (Items.Count == 0)
963 return;
965 Items.Sort ();
966 base.Refresh ();
969 public override string ToString ()
971 return base.ToString ();
974 protected virtual void WmReflectCommand (ref Message m)
978 protected override void WndProc (ref Message m)
980 base.WndProc (ref m);
983 #endregion Public Methods
985 #region Private Methods
987 private Size canvas_size;
989 private void LayoutListBox ()
991 if (!IsHandleCreated || suspend_layout)
992 return;
994 if (MultiColumn)
995 LayoutMultiColumn ();
996 else
997 LayoutSingleColumn ();
999 UpdateScrollBars ();
1000 last_visible_index = LastVisibleItem ();
1003 private void LayoutSingleColumn ()
1005 int height, width;
1007 switch (DrawMode) {
1008 case DrawMode.OwnerDrawVariable:
1009 height = 0;
1010 width = HorizontalExtent;
1011 for (int i = 0; i < Items.Count; i++) {
1012 height += GetItemHeight (i);
1014 break;
1016 case DrawMode.OwnerDrawFixed:
1017 height = Items.Count * ItemHeight;
1018 width = HorizontalExtent;
1019 break;
1021 case DrawMode.Normal:
1022 default:
1023 height = Items.Count * ItemHeight;
1024 width = 0;
1025 for (int i = 0; i < Items.Count; i++) {
1026 SizeF sz = DeviceContext.MeasureString (GetItemText (Items[i]), Font);
1027 if ((int) sz.Width > width)
1028 width = (int) sz.Width;
1030 break;
1033 canvas_size = new Size (width, height);
1036 private void LayoutMultiColumn ()
1038 int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
1039 row_count = usable_height / ItemHeight;
1040 if (row_count == 0)
1041 row_count = 1;
1042 int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1043 Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1044 if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
1045 usable_height = ClientRectangle.Height - hscrollbar.Height;
1046 row_count = usable_height / ItemHeight;
1047 cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1048 sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1050 canvas_size = sz;
1053 internal void Draw (Rectangle clip, Graphics dc)
1055 Theme theme = ThemeEngine.Current;
1057 if (hscrollbar.Visible && vscrollbar.Visible) {
1058 // Paint the dead space in the bottom right corner
1059 Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
1060 if (rect.IntersectsWith (clip))
1061 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
1064 dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
1066 if (Items.Count == 0)
1067 return;
1069 for (int i = top_index; i <= last_visible_index; i++) {
1070 Rectangle rect = GetItemDisplayRectangle (i, top_index);
1072 if (!clip.IntersectsWith (rect))
1073 continue;
1075 DrawItemState state = DrawItemState.None;
1077 if (SelectedIndices.Contains (i))
1078 state |= DrawItemState.Selected;
1080 if (has_focus && FocusedItem == i)
1081 state |= DrawItemState.Focus;
1083 if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
1084 rect.X -= hscrollbar.Value;
1085 rect.Width += hscrollbar.Value;
1088 OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, ForeColor, BackColor));
1092 // Converts a GetItemRectangle to a one that we can display
1093 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1095 Rectangle item_rect;
1096 Rectangle first_item_rect = GetItemRectangle (first_displayble);
1097 item_rect = GetItemRectangle (index);
1098 item_rect.X -= first_item_rect.X;
1099 item_rect.Y -= first_item_rect.Y;
1101 return item_rect;
1104 // Value Changed
1105 private void HorizontalScrollEvent (object sender, EventArgs e)
1107 if (multicolumn) {
1108 int top_item = top_index;
1109 int last_item = last_visible_index;
1111 top_index = RowCount * hscrollbar.Value;
1112 last_visible_index = LastVisibleItem ();
1114 if (top_item != top_index || last_item != last_visible_index)
1115 Invalidate (items_area);
1117 else {
1118 int old_offset = hbar_offset;
1119 hbar_offset = hscrollbar.Value;
1121 if (hbar_offset < 0)
1122 hbar_offset = 0;
1124 XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
1128 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
1129 // has screen coordinates
1130 private int IndexAtClientPoint (int x, int y)
1132 if (Items.Count == 0)
1133 return -1;
1135 if (x < 0)
1136 x = 0;
1137 else if (x > ClientRectangle.Right)
1138 x = ClientRectangle.Right;
1140 if (y < 0)
1141 y = 0;
1142 else if (y > ClientRectangle.Bottom)
1143 y = ClientRectangle.Bottom;
1145 for (int i = top_index; i <= last_visible_index; i++)
1146 if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
1147 return i;
1149 return -1;
1152 private int LastVisibleItem ()
1154 Rectangle item_rect;
1155 int top_y = items_area.Y + items_area.Height;
1156 int i = 0;
1158 if (top_index >= Items.Count)
1159 return top_index;
1161 for (i = top_index; i < Items.Count; i++) {
1163 item_rect = GetItemDisplayRectangle (i, top_index);
1164 if (MultiColumn) {
1166 if (item_rect.X > items_area.Width)
1167 return i - 1;
1169 else {
1170 if (item_rect.Y + item_rect.Height > top_y) {
1171 return i;
1175 return i - 1;
1178 private void UpdateTopItem ()
1180 if (MultiColumn) {
1181 int col = top_index / RowCount;
1183 if (col > hscrollbar.Maximum)
1184 hscrollbar.Value = hscrollbar.Maximum;
1185 else
1186 hscrollbar.Value = col;
1187 } else {
1188 int val = vscrollbar.Value;
1189 if (top_index > vscrollbar.Maximum)
1190 vscrollbar.Value = vscrollbar.Maximum;
1191 else
1192 vscrollbar.Value = top_index;
1193 Scroll (vscrollbar, vscrollbar.Value - top_index);
1194 XplatUI.ScrollWindow (Handle, items_area, 0, ItemHeight * (val - vscrollbar.Value), false);
1198 // Navigates to the indicated item and returns the new item
1199 private int NavigateItemVisually (ItemNavigation navigation)
1201 int page_size, columns, selected_index = -1;
1203 if (multicolumn) {
1204 columns = items_area.Width / ColumnWidthInternal;
1205 page_size = columns * RowCount;
1206 if (page_size == 0) {
1207 page_size = RowCount;
1209 } else {
1210 page_size = items_area.Height / ItemHeight;
1213 switch (navigation) {
1215 case ItemNavigation.PreviousColumn: {
1216 if (FocusedItem - RowCount < 0) {
1217 return -1;
1220 if (FocusedItem - RowCount < top_index) {
1221 top_index = FocusedItem - RowCount;
1222 UpdateTopItem ();
1225 selected_index = FocusedItem - RowCount;
1226 break;
1229 case ItemNavigation.NextColumn: {
1230 if (FocusedItem + RowCount >= Items.Count) {
1231 break;
1234 if (FocusedItem + RowCount > last_visible_index) {
1235 top_index = FocusedItem;
1236 UpdateTopItem ();
1239 selected_index = FocusedItem + RowCount;
1240 break;
1243 case ItemNavigation.First: {
1244 top_index = 0;
1245 selected_index = 0;
1246 UpdateTopItem ();
1247 break;
1250 case ItemNavigation.Last: {
1252 int rows = items_area.Height / ItemHeight;
1253 if (Items.Count < rows) {
1254 top_index = 0;
1255 selected_index = Items.Count - 1;
1256 UpdateTopItem ();
1257 } else {
1258 top_index = Items.Count - rows;
1259 selected_index = Items.Count - 1;
1260 UpdateTopItem ();
1262 break;
1265 case ItemNavigation.Next: {
1266 if (FocusedItem == Items.Count - 1)
1267 return -1;
1269 int bottom = 0;
1270 ArrayList heights = new ArrayList ();
1271 if (draw_mode == DrawMode.OwnerDrawVariable) {
1272 for (int i = top_index; i <= FocusedItem + 1; i++) {
1273 int h = GetItemHeight (i);
1274 bottom += h;
1275 heights.Add (h);
1277 } else {
1278 bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
1281 if (bottom >= items_area.Height) {
1282 int overhang = bottom - items_area.Height;
1284 int offset = 0;
1285 if (draw_mode == DrawMode.OwnerDrawVariable)
1286 while (overhang > 0)
1287 overhang -= (int) heights [offset];
1288 else
1289 offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
1290 top_index += offset;
1291 UpdateTopItem ();
1293 selected_index = FocusedItem + 1;
1294 break;
1297 case ItemNavigation.Previous: {
1298 if (FocusedItem > 0) {
1299 if (FocusedItem - 1 < top_index) {
1300 top_index--;
1301 UpdateTopItem ();
1303 selected_index = FocusedItem - 1;
1305 break;
1308 case ItemNavigation.NextPage: {
1309 if (Items.Count < page_size) {
1310 NavigateItemVisually (ItemNavigation.Last);
1311 break;
1314 if (FocusedItem + page_size - 1 >= Items.Count) {
1315 top_index = Items.Count - page_size;
1316 UpdateTopItem ();
1317 selected_index = Items.Count - 1;
1319 else {
1320 if (FocusedItem + page_size - 1 > last_visible_index) {
1321 top_index = FocusedItem;
1322 UpdateTopItem ();
1325 selected_index = FocusedItem + page_size - 1;
1328 break;
1331 case ItemNavigation.PreviousPage: {
1333 int rows = items_area.Height / ItemHeight;
1334 if (FocusedItem - (rows - 1) <= 0) {
1336 top_index = 0;
1337 UpdateTopItem ();
1338 SelectedIndex = 0;
1340 else {
1341 if (FocusedItem - (rows - 1) < top_index) {
1342 top_index = FocusedItem - (rows - 1);
1343 UpdateTopItem ();
1346 selected_index = FocusedItem - (rows - 1);
1349 break;
1351 default:
1352 break;
1355 return selected_index;
1359 private void OnGotFocus (object sender, EventArgs e)
1361 if (FocusedItem != -1)
1362 InvalidateItem (FocusedItem);
1365 private void OnLostFocus (object sender, EventArgs e)
1367 if (FocusedItem != -1)
1368 InvalidateItem (FocusedItem);
1371 private void OnKeyDownLB (object sender, KeyEventArgs e)
1373 int new_item = -1;
1375 if (Items.Count == 0)
1376 return;
1378 switch (e.KeyCode) {
1380 case Keys.ControlKey:
1381 ctrl_pressed = true;
1382 break;
1384 case Keys.ShiftKey:
1385 shift_pressed = true;
1386 break;
1388 case Keys.Home:
1389 new_item = NavigateItemVisually (ItemNavigation.First);
1390 break;
1392 case Keys.End:
1393 new_item = NavigateItemVisually (ItemNavigation.Last);
1394 break;
1396 case Keys.Up:
1397 new_item = NavigateItemVisually (ItemNavigation.Previous);
1398 break;
1400 case Keys.Down:
1401 new_item = NavigateItemVisually (ItemNavigation.Next);
1402 break;
1404 case Keys.PageUp:
1405 new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1406 break;
1408 case Keys.PageDown:
1409 new_item = NavigateItemVisually (ItemNavigation.NextPage);
1410 break;
1412 case Keys.Right:
1413 if (multicolumn == true) {
1414 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1416 break;
1418 case Keys.Left:
1419 if (multicolumn == true) {
1420 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1422 break;
1424 case Keys.Space:
1425 if (selection_mode == SelectionMode.MultiSimple) {
1426 SelectedItemFromNavigation (FocusedItem);
1428 break;
1431 default:
1432 break;
1435 if (new_item != -1) {
1436 FocusedItem = new_item;
1437 if (selection_mode != SelectionMode.MultiSimple && selection_mode != SelectionMode.None) {
1438 SelectedItemFromNavigation (new_item);
1443 private void OnKeyUpLB (object sender, KeyEventArgs e)
1445 switch (e.KeyCode) {
1446 case Keys.ControlKey:
1447 ctrl_pressed = false;
1448 break;
1449 case Keys.ShiftKey:
1450 shift_pressed = false;
1451 break;
1452 default:
1453 break;
1457 internal void InvalidateItem (int index)
1459 Rectangle bounds = GetItemDisplayRectangle (index, top_index);
1460 if (ClientRectangle.IntersectsWith (bounds))
1461 Invalidate (bounds);
1464 internal virtual void OnItemClick (int index)
1466 OnSelectedIndexChanged (EventArgs.Empty);
1467 OnSelectedValueChanged (EventArgs.Empty);
1470 int anchor = -1;
1471 int[] prev_selection;
1472 bool button_pressed = false;
1474 private void SelectExtended (int index)
1476 SuspendLayout ();
1478 ArrayList new_selection = new ArrayList ();
1479 int start = anchor < index ? anchor : index;
1480 int end = anchor > index ? anchor : index;
1481 for (int i = start; i <= end; i++)
1482 new_selection.Add (i);
1484 if (ctrl_pressed)
1485 foreach (int i in prev_selection)
1486 if (!selection.Contains (i))
1487 new_selection.Add (i);
1489 foreach (int i in SelectedIndices)
1490 if (!new_selection.Contains (i))
1491 UnSelectItem (i, true);
1493 foreach (int i in new_selection)
1494 if (!SelectedIndices.Contains (i))
1495 SelectItem (i);
1496 ResumeLayout ();
1499 private void OnMouseDownLB (object sender, MouseEventArgs e)
1501 int index = IndexAtClientPoint (e.X, e.Y);
1503 if (index == -1)
1504 return;
1506 switch (SelectionMode) {
1507 case SelectionMode.One:
1508 if (SelectedIndex != index) {
1509 UnSelectItem (SelectedIndex, true);
1510 SelectItem (index);
1512 selected_index = index;
1513 break;
1515 case SelectionMode.MultiSimple:
1516 if (SelectedIndices.Contains (index))
1517 UnSelectItem (index, true);
1518 else
1519 SelectItem (index);
1520 break;
1522 case SelectionMode.MultiExtended:
1523 shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1524 ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1526 if (ctrl_pressed) {
1527 prev_selection = new int [selection.Count];
1528 SelectedIndices.CopyTo (prev_selection, 0);
1529 } else
1530 ClearSelected ();
1532 if (!shift_pressed)
1533 anchor = index;
1535 SelectExtended (index);
1536 break;
1538 case SelectionMode.None:
1539 default:
1540 return;
1543 button_pressed = true;
1544 FocusedItem = index;
1547 private void OnMouseMoveLB (object sender, MouseEventArgs e)
1549 if (!button_pressed)
1550 return;
1552 int index = IndexAtClientPoint (e.X, e.Y);
1554 switch (SelectionMode) {
1555 case SelectionMode.One:
1556 if (index == selected_index)
1557 return;
1559 UnSelectItem (SelectedIndex, true);
1560 SelectItem (index);
1561 selected_index = index;
1562 break;
1564 case SelectionMode.MultiSimple:
1565 break;
1567 case SelectionMode.MultiExtended:
1568 SelectExtended (index);
1569 break;
1571 case SelectionMode.None:
1572 default:
1573 return;
1576 FocusedItem = index;
1579 private void OnMouseUpLB (object sender, MouseEventArgs e)
1581 if (e.Clicks > 1)
1582 OnDoubleClick (EventArgs.Empty);
1583 else if (e.Clicks == 1)
1584 OnClick (EventArgs.Empty);
1586 if (!button_pressed)
1587 return;
1589 int index = IndexAtClientPoint (e.X, e.Y);
1590 OnItemClick (index);
1591 button_pressed = ctrl_pressed = shift_pressed = false;
1594 private void Scroll (ScrollBar scrollbar, int delta)
1596 if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
1597 return;
1599 int max;
1600 if (scrollbar == hscrollbar)
1601 max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
1602 else
1603 max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
1605 int val = scrollbar.Value + delta;
1606 if (val > max)
1607 val = max;
1608 else if (val < scrollbar.Minimum)
1609 val = scrollbar.Minimum;
1610 scrollbar.Value = val;
1613 private void OnMouseWheelLB (object sender, MouseEventArgs me)
1615 if (Items.Count == 0)
1616 return;
1618 int lines = me.Delta / 120;
1620 if (MultiColumn)
1621 Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
1622 else
1623 Scroll (vscrollbar, -lines);
1626 internal override void OnPaintInternal (PaintEventArgs pevent)
1628 if (suspend_layout)
1629 return;
1631 Draw (pevent.ClipRectangle, pevent.Graphics);
1634 internal void RepositionScrollBars ()
1636 if (vscrollbar.is_visible) {
1637 vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
1638 vscrollbar.Location = new Point (items_area.Width, 0);
1641 if (hscrollbar.is_visible) {
1642 hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
1643 hscrollbar.Location = new Point (0, items_area.Height);
1647 // Add an item in the Selection array and marks it visually as selected
1648 private void SelectItem (int index)
1650 if (index == -1 || SelectedIndices.Contains (index))
1651 return;
1653 selection.Add (Items[index]);
1654 InvalidateItem (index);
1657 // An item navigation operation (mouse or keyboard) has caused to select a new item
1658 internal void SelectedItemFromNavigation (int index)
1660 switch (SelectionMode) {
1661 case SelectionMode.None: // Do nothing
1662 break;
1663 case SelectionMode.One: {
1664 SelectedIndex = index;
1665 break;
1667 case SelectionMode.MultiSimple: {
1668 if (SelectedIndex == -1) {
1669 SelectedIndex = index;
1670 } else {
1672 if (SelectedIndices.Contains (index))
1673 UnSelectItem (index, true);
1674 else {
1675 SelectItem (index);
1676 OnSelectedIndexChanged (new EventArgs ());
1677 OnSelectedValueChanged (new EventArgs ());
1680 break;
1683 case SelectionMode.MultiExtended: {
1684 if (SelectedIndex == -1) {
1685 SelectedIndex = index;
1686 } else {
1688 if (ctrl_pressed == false && shift_pressed == false) {
1689 ClearSelected ();
1692 if (shift_pressed == true) {
1693 ShiftSelection (index);
1694 } else { // ctrl_pressed or single item
1695 SelectItem (index);
1698 OnSelectedIndexChanged (new EventArgs ());
1699 OnSelectedValueChanged (new EventArgs ());
1701 break;
1704 default:
1705 break;
1709 private void ShiftSelection (int index)
1711 int shorter_item = -1, dist = Items.Count + 1, cur_dist;
1713 foreach (int idx in selected_indices) {
1714 if (idx > index) {
1715 cur_dist = idx - index;
1717 else {
1718 cur_dist = index - idx;
1721 if (cur_dist < dist) {
1722 dist = cur_dist;
1723 shorter_item = idx;
1727 if (shorter_item != -1) {
1728 int start, end;
1730 if (shorter_item > index) {
1731 start = index;
1732 end = shorter_item;
1733 } else {
1734 start = shorter_item;
1735 end = index;
1738 ClearSelected ();
1739 for (int idx = start; idx <= end; idx++) {
1740 SelectItem (idx);
1745 internal int FocusedItem {
1746 get { return focused_item; }
1747 set {
1748 if (focused_item == value)
1749 return;
1751 int prev = focused_item;
1753 focused_item = value;
1755 if (has_focus == false)
1756 return;
1758 if (prev != -1)
1759 InvalidateItem (prev);
1761 if (value != -1)
1762 InvalidateItem (value);
1766 // Removes an item in the Selection array and marks it visually as unselected
1767 private void UnSelectItem (int index, bool remove)
1769 if (index == -1)
1770 return;
1772 if (remove)
1773 selection.Remove (Items[index]);
1775 InvalidateItem (index);
1778 StringFormat string_format;
1779 internal StringFormat StringFormat {
1780 get {
1781 if (string_format == null) {
1782 string_format = new StringFormat ();
1783 if (RightToLeft == RightToLeft.Yes)
1784 string_format.Alignment = StringAlignment.Far;
1785 else
1786 string_format.Alignment = StringAlignment.Near;
1787 if (use_tabstops)
1788 string_format.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
1790 return string_format;
1795 internal virtual void CollectionChanged ()
1797 if (sorted)
1798 Sort ();
1800 if (Items.Count == 0) {
1801 selected_index = -1;
1802 focused_item = -1;
1803 top_index = 0;
1806 if (!IsHandleCreated || suspend_layout)
1807 return;
1809 LayoutListBox ();
1811 base.Refresh ();
1814 private void UpdateListBoxBounds ()
1816 if (requested_height == -1)
1817 return;
1819 SetBounds(0, 0, 0, requested_height, BoundsSpecified.Height);
1822 private void UpdateScrollBars ()
1824 items_area = ClientRectangle;
1825 if (UpdateHorizontalScrollBar ()) {
1826 items_area.Height -= hscrollbar.Height;
1827 if (UpdateVerticalScrollBar ()) {
1828 items_area.Width -= vscrollbar.Width;
1829 UpdateHorizontalScrollBar ();
1831 } else if (UpdateVerticalScrollBar ()) {
1832 items_area.Width -= vscrollbar.Width;
1833 if (UpdateHorizontalScrollBar ()) {
1834 items_area.Height -= hscrollbar.Height;
1835 UpdateVerticalScrollBar ();
1839 RepositionScrollBars ();
1842 /* Determines if the horizontal scrollbar has to be displyed */
1843 private bool UpdateHorizontalScrollBar ()
1845 bool show = false;
1846 bool enabled = true;
1848 if (MultiColumn) {
1849 if (canvas_size.Width > items_area.Width) {
1850 show = true;
1851 hscrollbar.Maximum = canvas_size.Width / ColumnWidthInternal - 1;
1852 } else if (ScrollAlwaysVisible == true) {
1853 enabled = false;
1854 show = true;
1855 hscrollbar.Maximum = 0;
1857 } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
1858 show = true;
1859 hscrollbar.Maximum = canvas_size.Width;
1860 hscrollbar.LargeChange = items_area.Width;
1863 hbar_offset = hscrollbar.Value;
1864 hscrollbar.Enabled = enabled;
1865 hscrollbar.Visible = show;
1867 return show;
1870 /* Determines if the vertical scrollbar has to be displyed */
1871 private bool UpdateVerticalScrollBar ()
1873 if (MultiColumn || Items.Count == 0) {
1874 vscrollbar.Visible = false;
1875 return false;
1878 bool show = false;
1879 bool enabled = true;
1880 if (canvas_size.Height > items_area.Height) {
1881 show = true;
1882 vscrollbar.Maximum = Items.Count - 1;
1883 vscrollbar.LargeChange = items_area.Height / ItemHeight;
1884 } else if (ScrollAlwaysVisible) {
1885 show = true;
1886 enabled = false;
1887 vscrollbar.Maximum = 0;
1890 vscrollbar.Enabled = enabled;
1891 vscrollbar.Visible = show;
1893 return show;
1896 // Value Changed
1897 private void VerticalScrollEvent (object sender, EventArgs e)
1899 int top_item = top_index;
1901 top_index = /*row_count + */ vscrollbar.Value;
1902 last_visible_index = LastVisibleItem ();
1904 int diff = top_item - top_index;
1906 XplatUI.ScrollWindow (Handle, items_area, 0, ItemHeight * diff, false);
1909 #endregion Private Methods
1911 [ListBindable (false)]
1912 public class ObjectCollection : IList, ICollection, IEnumerable
1914 internal class ListObjectComparer : IComparer
1916 public int Compare (object a, object b)
1918 string str1 = a.ToString ();
1919 string str2 = b.ToString ();
1920 return str1.CompareTo (str2);
1924 private ListBox owner;
1925 internal ArrayList object_items = new ArrayList ();
1927 public ObjectCollection (ListBox owner)
1929 this.owner = owner;
1932 public ObjectCollection (ListBox owner, object[] obj)
1934 this.owner = owner;
1935 AddRange (obj);
1938 public ObjectCollection (ListBox owner, ObjectCollection obj)
1940 this.owner = owner;
1941 AddRange (obj);
1944 #region Public Properties
1945 public int Count {
1946 get { return object_items.Count; }
1949 public bool IsReadOnly {
1950 get { return false; }
1953 [Browsable(false)]
1954 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1955 public virtual object this [int index] {
1956 get {
1957 if (index < 0 || index >= Count)
1958 throw new ArgumentOutOfRangeException ("Index of out range");
1960 return object_items[index];
1962 set {
1963 if (index < 0 || index >= Count)
1964 throw new ArgumentOutOfRangeException ("Index of out range");
1965 if (value == null)
1966 throw new ArgumentNullException ("value");
1968 object_items[index] = value;
1969 owner.CollectionChanged ();
1973 bool ICollection.IsSynchronized {
1974 get { return false; }
1977 object ICollection.SyncRoot {
1978 get { return this; }
1981 bool IList.IsFixedSize {
1982 get { return false; }
1985 #endregion Public Properties
1987 #region Public Methods
1988 public int Add (object item)
1990 int idx;
1992 idx = AddItem (item);
1993 owner.CollectionChanged ();
1994 return idx;
1997 public void AddRange (object[] items)
1999 foreach (object mi in items)
2000 AddItem (mi);
2002 owner.CollectionChanged ();
2005 public void AddRange (ObjectCollection col)
2007 foreach (object mi in col)
2008 AddItem (mi);
2010 owner.CollectionChanged ();
2013 internal void AddRange (IList list)
2015 foreach (object mi in list)
2016 AddItem (mi);
2018 owner.CollectionChanged ();
2021 public virtual void Clear ()
2023 owner.selection.Clear ();
2024 object_items.Clear ();
2025 owner.CollectionChanged ();
2027 public bool Contains (object obj)
2029 return object_items.Contains (obj);
2032 public void CopyTo (object[] dest, int arrayIndex)
2034 object_items.CopyTo (dest, arrayIndex);
2037 void ICollection.CopyTo (Array dest, int index)
2039 object_items.CopyTo (dest, index);
2042 public IEnumerator GetEnumerator ()
2044 return object_items.GetEnumerator ();
2047 int IList.Add (object item)
2049 return Add (item);
2052 public int IndexOf (object value)
2054 return object_items.IndexOf (value);
2057 public void Insert (int index, object item)
2059 if (index < 0 || index > Count)
2060 throw new ArgumentOutOfRangeException ("Index of out range");
2062 owner.BeginUpdate ();
2063 object_items.Insert (index, item);
2064 owner.CollectionChanged ();
2065 owner.EndUpdate ();
2068 public void Remove (object value)
2070 RemoveAt (IndexOf (value));
2073 public void RemoveAt (int index)
2075 if (index < 0 || index >= Count)
2076 throw new ArgumentOutOfRangeException ("Index of out range");
2078 owner.selection.Remove (object_items [index]);
2079 object_items.RemoveAt (index);
2080 owner.CollectionChanged ();
2082 #endregion Public Methods
2084 #region Private Methods
2085 internal int AddItem (object item)
2087 if (item == null)
2088 throw new ArgumentNullException ("item");
2090 int cnt = object_items.Count;
2091 object_items.Add (item);
2092 return cnt;
2095 internal void Sort ()
2097 object_items.Sort (new ListObjectComparer ());
2100 #endregion Private Methods
2103 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2105 private ListBox owner;
2107 public SelectedIndexCollection (ListBox owner)
2109 this.owner = owner;
2112 #region Public Properties
2113 [Browsable (false)]
2114 public int Count {
2115 get { return owner.selection.Count; }
2118 public bool IsReadOnly {
2119 get { return true; }
2122 public int this [int index] {
2123 get {
2124 if (index < 0 || index >= Count)
2125 throw new ArgumentOutOfRangeException ("Index of out range");
2127 return owner.Items.IndexOf (owner.selection [index]);
2131 bool ICollection.IsSynchronized {
2132 get { return true; }
2135 bool IList.IsFixedSize{
2136 get { return true; }
2139 object ICollection.SyncRoot {
2140 get { return this; }
2143 #endregion Public Properties
2145 #region Public Methods
2146 public bool Contains (int selectedIndex)
2148 foreach (object o in owner.selection)
2149 if (owner.Items.IndexOf (o) == selectedIndex)
2150 return true;
2151 return false;
2154 public void CopyTo (Array dest, int index)
2156 foreach (object o in owner.selection)
2157 dest.SetValue(owner.Items.IndexOf (o), index++);
2160 public IEnumerator GetEnumerator ()
2162 //FIXME: write an enumerator that uses owner.selection.GetEnumerator
2163 // so that invalidation is write on selection changes
2164 ArrayList indices = new ArrayList ();
2165 foreach (object o in owner.selection)
2166 indices.Add (owner.Items.IndexOf (o));
2167 return indices.GetEnumerator ();
2170 int IList.Add (object obj)
2172 throw new NotSupportedException ();
2175 void IList.Clear ()
2177 throw new NotSupportedException ();
2180 bool IList.Contains (object selectedIndex)
2182 return Contains ((int)selectedIndex);
2185 int IList.IndexOf (object selectedIndex)
2187 return IndexOf ((int) selectedIndex);
2190 void IList.Insert (int index, object value)
2192 throw new NotSupportedException ();
2195 void IList.Remove (object value)
2197 throw new NotSupportedException ();
2200 void IList.RemoveAt (int index)
2202 throw new NotSupportedException ();
2205 object IList.this[int index]{
2206 get {return owner.Items.IndexOf (owner.selection [index]); }
2207 set {throw new NotImplementedException (); }
2210 public int IndexOf (int selectedIndex)
2212 for (int i = 0; i < owner.selection.Count; i++)
2213 if (owner.Items.IndexOf (owner.selection [i]) == selectedIndex)
2214 return i;
2215 return -1;
2217 #endregion Public Methods
2220 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2222 private ListBox owner;
2224 public SelectedObjectCollection (ListBox owner)
2226 this.owner = owner;
2229 #region Public Properties
2230 public int Count {
2231 get { return owner.selection.Count; }
2234 public bool IsReadOnly {
2235 get { return true; }
2238 [Browsable(false)]
2239 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2240 public object this [int index] {
2241 get {
2242 if (index < 0 || index >= Count)
2243 throw new ArgumentOutOfRangeException ("Index of out range");
2245 return owner.selection [index];
2247 set {throw new NotSupportedException ();}
2250 bool ICollection.IsSynchronized {
2251 get { return true; }
2254 object ICollection.SyncRoot {
2255 get { return this; }
2258 bool IList.IsFixedSize {
2259 get { return true; }
2262 #endregion Public Properties
2264 #region Public Methods
2265 public bool Contains (object selectedObject)
2267 return owner.selection.Contains (selectedObject);
2270 public void CopyTo (Array dest, int index)
2272 owner.selection.CopyTo (dest, index);
2275 int IList.Add (object value)
2277 throw new NotSupportedException ();
2280 void IList.Clear ()
2282 throw new NotSupportedException ();
2285 void IList.Insert (int index, object value)
2287 throw new NotSupportedException ();
2290 void IList.Remove (object value)
2292 throw new NotSupportedException ();
2295 void IList.RemoveAt (int index)
2297 throw new NotSupportedException ();
2300 public int IndexOf (object item)
2302 return owner.selection.IndexOf (item);
2305 public IEnumerator GetEnumerator ()
2307 return owner.selection.GetEnumerator ();
2310 #endregion Public Methods