2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListBox.cs
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.
11 //
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.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //
25 // TODO:
26 //      - Keyboard navigation
27 //      - Horizontal item scroll
28 //      - Performance testing
29 //
30 //
31
32 // NOT COMPLETE
33
34 using System;
35 using System.Drawing;
36 using System.Collections;
37 using System.ComponentModel;
38 using System.Reflection;
39
40 namespace System.Windows.Forms
41 {
42
43         public class ListBox : ListControl
44         {
45                 internal class ListBoxInfo
46                 {
47                         internal int item_height;               /* Item's height */
48                         internal int top_item;                  /* First item that we show the in the current page */
49                         internal int last_item;                 /* Last visible item */
50                         internal int page_size;                 /* Number of listbox items per page. In MultiColumn listbox indicates items per column */
51                         internal Rectangle textdrawing_rect;    /* Displayable Client Rectangle minus the scrollbars and with IntegralHeight calculated*/
52                         internal bool show_verticalsb;          /* Is Vertical scrollbar show it? */
53                         internal bool show_horizontalsb;        /* Is Horizontal scrollbar show it? */
54                         internal Rectangle client_rect;         /* Client Rectangle. Usually = ClientRectangle except when IntegralHeight has been applied*/
55                         internal int max_itemwidth;             /* Maxium item width within the listbox */
56
57                         public ListBoxInfo ()
58                         {
59                                 last_item = 0;
60                                 item_height = 0;
61                                 top_item = 0;
62                                 page_size = 0;
63                                 max_itemwidth = 0;
64                                 show_verticalsb = false;
65                                 show_horizontalsb = false;
66                         }
67                 }
68
69                 internal class ListBoxItem
70                 {
71                         internal int Index;
72                         internal bool Selected;
73                         internal int ItemHeight;                /* Only used for OwnerDrawVariable */
74                         internal CheckState State;
75
76                         public ListBoxItem (int index)
77                         {
78                                 Index = index;
79                                 Selected = false;
80                                 ItemHeight = -1;
81                                 State = CheckState.Unchecked;
82                         }
83                 }
84
85                 internal enum ItemNavigation
86                 {
87                         First,
88                         Last,
89                         Next,
90                         Previous,
91                         NextPage,
92                         PreviousPage,
93                         PreviousColumn,
94                         NextColumn
95                 }
96
97                 private BorderStyle border_style;
98                 private int column_width;
99                 private DrawMode draw_mode;
100                 private int horizontal_extent;
101                 private bool horizontal_scrollbar;
102                 private bool integral_height;
103                 private bool multicolumn;
104                 private bool scroll_always_visible;
105                 private int selected_index;             
106                 private SelectedIndexCollection selected_indices;               
107                 private SelectedObjectCollection selected_items;
108                 private SelectionMode selection_mode;
109                 private bool sorted;
110                 private bool use_tabstops;
111                 private int preferred_height;
112                 private int top_index;
113                 private int column_width_internal;
114                 private VScrollBar vscrollbar_ctrl;
115                 private HScrollBar hscrollbar_ctrl;
116                 private bool suspend_ctrlupdate;
117                 private bool ctrl_pressed;
118                 private bool shift_pressed;
119                 private bool has_focus;
120                 
121                 internal int focused_item;
122                 internal StringFormat string_format;
123                 internal ListBoxInfo listbox_info;
124                 internal ObjectCollection items;
125
126                 public ListBox ()
127                 {
128                         border_style = BorderStyle.Fixed3D;                     \r
129                         draw_mode = DrawMode.Normal;\r
130                         horizontal_extent = 0;\r
131                         horizontal_scrollbar = false;\r
132                         integral_height = true;\r
133                         multicolumn = false;\r
134                         preferred_height = 7;\r
135                         scroll_always_visible = false;\r
136                         selected_index = -1;
137                         focused_item = -1;\r
138                         selection_mode = SelectionMode.One;\r
139                         sorted = false;\r
140                         top_index = 0;\r
141                         use_tabstops = true;
142                         BackColor = ThemeEngine.Current.ColorWindow;
143                         ColumnWidth = 0;
144                         suspend_ctrlupdate = false;
145                         ctrl_pressed = false;
146                         shift_pressed = false;
147                         has_focus = false;
148
149                         items = new ObjectCollection (this);
150                         selected_indices = new SelectedIndexCollection (this);
151                         selected_items = new SelectedObjectCollection (this);
152                         listbox_info = new ListBoxInfo ();
153                         string_format = new StringFormat ();
154                         listbox_info.item_height = FontHeight;
155
156                         /* Vertical scrollbar */
157                         vscrollbar_ctrl = new VScrollBar ();
158                         vscrollbar_ctrl.Minimum = 0;
159                         vscrollbar_ctrl.SmallChange = 1;
160                         vscrollbar_ctrl.LargeChange = 1;
161                         vscrollbar_ctrl.Maximum = 0;
162                         vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent);
163                         vscrollbar_ctrl.Visible = false;
164
165                         /* Horizontal scrollbar */
166                         hscrollbar_ctrl = new HScrollBar ();
167                         hscrollbar_ctrl.Minimum = 0;
168                         hscrollbar_ctrl.SmallChange = 1;
169                         hscrollbar_ctrl.LargeChange = 1;
170                         hscrollbar_ctrl.Maximum = 0;
171                         hscrollbar_ctrl.Visible = false;
172                         hscrollbar_ctrl.ValueChanged += new EventHandler (HorizontalScrollEvent);
173
174                         /* Events */
175                         MouseDown += new MouseEventHandler (OnMouseDownLB);
176                         KeyDown += new KeyEventHandler (OnKeyDownLB);
177                         KeyUp += new KeyEventHandler (OnKeyUpLB);
178                         GotFocus += new EventHandler (OnGotFocus);
179                         LostFocus += new EventHandler (OnLostFocus);
180
181                         UpdateFormatString ();
182                 }
183
184                 #region Events
185                 public new event EventHandler BackgroundImageChanged;
186                 public new event EventHandler Click;
187                 public event DrawItemEventHandler DrawItem;
188                 public event MeasureItemEventHandler MeasureItem;
189                 public new event PaintEventHandler Paint;
190                 public event EventHandler SelectedIndexChanged;
191                 public new event EventHandler TextChanged;
192                 #endregion // Events
193
194                 #region Public Properties
195                 public override Color BackColor {
196                         get { return base.BackColor; }
197                         set {
198                                 if (base.BackColor == value)
199                                         return;
200
201                                 base.BackColor = value;
202                                 base.Refresh ();        // Careful. Calling the base method is not the same that calling 
203                         }                               // the overriden one that refresh also all the items
204                 }
205
206                 public override Image BackgroundImage {
207                         get { return base.BackgroundImage; }
208                         set {
209                                 if (base.BackgroundImage == value)
210                                         return;
211
212                                 base.BackgroundImage = value;
213
214                                 if (BackgroundImageChanged != null)
215                                         BackgroundImageChanged (this, EventArgs.Empty);
216
217                                 base.Refresh ();
218                         }
219                 }
220
221                 public BorderStyle BorderStyle {
222                         get { return border_style; }
223
224                         set {
225                                 if (!Enum.IsDefined (typeof (BorderStyle), value))
226                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value));
227
228                                 if (border_style == value)
229                                         return;
230
231                                 border_style = value;
232                                 base.Refresh ();
233                         }
234                 }
235
236                 public int ColumnWidth {
237                         get { return column_width; }
238                         set {
239                                 if (column_width < 0)
240                                         throw new ArgumentException ("A value less than zero is assigned to the property.");
241
242                                 column_width = value;
243
244                                 if (value == 0)
245                                         ColumnWidthInternal = 120;
246                                 else
247                                         ColumnWidthInternal = value;
248
249                                 base.Refresh ();
250                         }
251                 }
252
253                 protected override CreateParams CreateParams {
254                         get { return base.CreateParams;}
255                 }
256
257                 protected override Size DefaultSize {
258                         get { return new Size (120, 96); }
259                 }
260
261                 public virtual DrawMode DrawMode {
262                         get { return draw_mode; }
263
264                         set {
265                                 if (!Enum.IsDefined (typeof (DrawMode), value))
266                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
267                                         
268                                 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
269                                         throw new InvalidEnumArgumentException ("Cannot have variable height and multicolumn");
270
271                                 if (draw_mode == value)
272                                         return;
273
274                                 draw_mode = value;
275                                 base.Refresh ();
276                         }
277                 }
278
279                 public override Color ForeColor {
280                         get { return base.ForeColor; }
281                         set {
282
283                                 if (base.ForeColor == value)
284                                         return;
285
286                                 base.ForeColor = value;
287                                 base.Refresh ();
288                         }
289                 }
290
291                 public int HorizontalExtent {
292                         get { return horizontal_extent; }
293                         set {
294                                 if (horizontal_extent == value)
295                                         return;
296
297                                 horizontal_extent = value;
298                                 base.Refresh ();
299                         }
300                 }
301
302                 public bool HorizontalScrollbar {
303                         get { return horizontal_scrollbar; }
304                         set {
305                                 if (horizontal_scrollbar == value)
306                                         return;
307
308                                 horizontal_scrollbar = value;
309                                 UpdateShowHorizontalScrollBar ();
310                                 base.Refresh ();
311                         }
312                 }
313
314                 public bool IntegralHeight {
315                         get { return integral_height; }
316                         set {
317                                 if (integral_height == value)
318                                         return;
319
320                                 integral_height = value;
321                                 CalcClientArea ();
322                         }
323                 }
324
325                 public virtual int ItemHeight {
326                         get { return listbox_info.item_height; }
327                         set {
328                                 if (value > 255)
329                                         throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
330
331                                 listbox_info.item_height = value;
332                                 CalcClientArea ();
333                         }
334                 }
335
336                 public ObjectCollection Items {
337                         get { return items; }
338                 }
339
340                 public bool MultiColumn {
341                         get { return multicolumn; }
342                         set {
343                                 if (multicolumn == value)
344                                         return;
345
346                                 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
347                                         throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
348
349                                 multicolumn = value;
350                                 UpdateShowVerticalScrollBar (); /* the needs for scrollbars may change */
351                                 UpdateShowHorizontalScrollBar ();
352                                 base.Refresh ();
353                         }
354                 }
355
356                 public int PreferredHeight {
357                         get { return preferred_height;}
358                 }
359
360                 public override RightToLeft RightToLeft {
361                         get { return base.RightToLeft; }
362                         set {
363                                 if (base.RightToLeft == value)
364                                         return;
365
366                                 base.RightToLeft = value;
367                                 UpdateFormatString ();
368                                 base.Refresh ();
369                         }
370                 }
371
372                 // Only afects the Vertical ScrollBar
373                 public bool ScrollAlwaysVisible {
374                         get { return scroll_always_visible; }
375                         set {
376                                 if (scroll_always_visible == value)
377                                         return;
378
379                                 scroll_always_visible = value;
380                                 UpdateShowVerticalScrollBar ();
381                                 UpdateShowHorizontalScrollBar ();
382                         }
383                 }
384
385                 public override int SelectedIndex {
386                         get { return selected_index;}
387                         set {
388                                 if (value < -1 || value >= Items.Count)
389                                         throw new ArgumentOutOfRangeException ("Index of out range");
390
391                                 if (SelectionMode == SelectionMode.None)
392                                         throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
393
394                                 if (selected_index == value)
395                                         return;
396
397                                 if (SelectionMode == SelectionMode.One)
398                                         UnSelectItem (selected_index, true);
399
400                                 SelectItem (value);
401                                 selected_index = value;
402                                 focused_item = value;
403                                 OnSelectedIndexChanged  (new EventArgs ());
404                         }
405                 }
406
407                 public SelectedIndexCollection SelectedIndices {
408                         get { return selected_indices; }
409                 }
410
411                 public object SelectedItem {
412                         get {
413                                 if (SelectedItems.Count > 0)
414                                         return SelectedItems[0];
415                                 else
416                                         return null;
417                         }
418                         set {
419                                 
420                                 int index = Items.IndexOf (value);
421
422                                 if (index == -1)
423                                         return;
424                                         
425                                 if (index != SelectedIndex) {
426                                         SelectedIndex = index;
427                                 }
428                         }
429                 }
430
431                 public SelectedObjectCollection SelectedItems {
432                         get {return selected_items;}
433                 }
434
435                 public virtual SelectionMode SelectionMode {
436                         get { return selection_mode; }
437                         set {
438                                 if (!Enum.IsDefined (typeof (SelectionMode), value))
439                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
440
441                                 if (selection_mode == value)
442                                         return;
443
444                                 selection_mode = value;
445                                 base.Refresh ();
446                         }
447                 }
448
449                 public bool Sorted {
450                         get { return sorted; }
451
452                         set {
453                                 if (sorted == value)
454                                         return;
455
456                                 sorted = value;
457                                 Sort ();
458                         }
459                 }
460
461                 public override string Text {
462                         get {
463                                 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
464                                         return Items[SelectedIndex].ToString ();
465
466                                 return base.Text;
467                         }
468                         set {
469
470                                 base.Text = value;
471
472                                 if (SelectionMode == SelectionMode.None)
473                                         return;
474
475                                 int index;
476
477                                 index = FindStringExact (value);
478
479                                 if (index == -1)
480                                         return;
481
482                                 SelectedIndex = index;
483                         }
484                 }
485
486                 public int TopIndex {
487                         get { return top_index;}
488                         set {
489                                 if (value == top_index)
490                                         return;
491
492                                 if (value < 0 || value >= Items.Count)
493                                         return;
494
495                                 value = top_index;
496                                 base.Refresh ();
497                         }
498                 }
499
500                 public bool UseTabStops {
501                         get { return use_tabstops; }
502
503                         set {
504                                 if (use_tabstops == value)
505                                         return;
506
507                                 use_tabstops = value;
508                                 UpdateFormatString ();
509                                 base.Refresh ();
510                         }
511                 }
512
513                 #endregion Public Properties
514
515                 #region Private Properties
516
517                 internal ListBoxInfo LBoxInfo {
518                         get { return listbox_info; }
519                 }
520
521                 private int ColumnWidthInternal {
522                         get { return column_width_internal; }
523                         set { column_width_internal = value; }
524                 }
525
526                 #endregion Private Properties
527
528                 #region Public Methods
529                 protected virtual void AddItemsCore (object[] value)
530                 {
531                         Items.AddRange (value);
532                 }
533
534                 public void BeginUpdate ()
535                 {
536                         suspend_ctrlupdate = true;
537                 }
538
539                 public void ClearSelected ()
540                 {
541                         foreach (int i in selected_indices) {
542                                 UnSelectItem (i, false);
543                         }
544
545                         selected_indices.ClearIndices ();
546                         selected_items.ClearObjects ();
547                 }
548
549                 protected virtual ObjectCollection CreateItemCollection ()
550                 {
551                         return new ObjectCollection (this);
552                 }
553
554                 public void EndUpdate ()
555                 {
556                         suspend_ctrlupdate = false;
557                         UpdateItemInfo (false, -1, -1);
558                         base.Refresh ();
559                 }
560
561                 public int FindString (String s)
562                 {
563                         return FindString (s, 0);
564                 }
565
566                 public int FindString (string s,  int startIndex)
567                 {
568                         for (int i = startIndex; i < Items.Count; i++) {
569                                 if ((Items[i].ToString ()).StartsWith (s))
570                                         return i;
571                         }
572
573                         return -1;
574                 }
575
576                 public int FindStringExact (string s)
577                 {
578                         return FindStringExact (s, 0);
579                 }
580
581                 public int FindStringExact (string s,  int startIndex)
582                 {
583                         for (int i = startIndex; i < Items.Count; i++) {
584                                 if ((Items[i].ToString ()).Equals (s))
585                                         return i;
586                         }
587
588                         return -1;
589                 }
590
591                 public int GetItemHeight (int index)
592                 {
593                         if (index < 0 || index >= Items.Count)
594                                 throw new ArgumentOutOfRangeException ("Index of out range");
595                                 
596                         if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
597                                 
598                                 if ((Items.GetListBoxItem (index)).ItemHeight != -1) {
599                                         return (Items.GetListBoxItem (index)).ItemHeight;
600                                 }
601                                 
602                                 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
603                                 OnMeasureItem (args);
604                                 (Items.GetListBoxItem (index)).ItemHeight = args.ItemHeight;
605                                 return args.ItemHeight;
606                         }
607
608                         return ItemHeight;
609                 }
610
611                 public Rectangle GetItemRectangle (int index)
612                 {
613                         if (index < 0 || index >= Items.Count)
614                                 throw new  ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
615
616                         Rectangle rect = new Rectangle ();
617
618                         if (MultiColumn == false) {
619
620                                 rect.X = 0;                             
621                                 rect.Height = GetItemHeight (index);
622                                 rect.Width = listbox_info.textdrawing_rect.Width;
623                                 
624                                 if (DrawMode == DrawMode.OwnerDrawVariable) {
625                                         rect.Y = 0;
626                                         for (int i = 0; i < index; i++) {
627                                                 rect.Y += GetItemHeight (i);
628                                         }                                       
629                                 } else {
630                                         rect.Y = ItemHeight * index;    
631                                 }
632                                 
633                         }
634                         else {
635                                 int which_page;
636
637                                 which_page = index / listbox_info.page_size;
638                                 rect.Y = (index % listbox_info.page_size) * ItemHeight;
639                                 rect.X = which_page * ColumnWidthInternal;
640                                 rect.Height = ItemHeight;
641                                 rect.Width = ColumnWidthInternal;
642                         }
643
644                         return rect;
645                 }
646
647                 public bool GetSelected (int index)
648                 {
649                         if (index < 0 || index >= Items.Count)
650                                 throw new ArgumentOutOfRangeException ("Index of out range");
651
652                         return (Items.GetListBoxItem (index)).Selected;
653                 }
654
655                 public int IndexFromPoint (Point p)
656                 {
657                         return IndexFromPoint (p.X, p.Y);
658                 }
659
660                 // Only returns visible points
661                 public int IndexFromPoint (int x, int y)
662                 {
663                         for (int i = LBoxInfo.top_item; i < LBoxInfo.last_item; i++) {
664                                 if (GetItemRectangle (i).Contains (x,y) == true)
665                                         return i;
666                         }
667
668                         return -1;
669                 }
670
671                 protected override void OnChangeUICues (UICuesEventArgs e)
672                 {
673                         base.OnChangeUICues (e);
674                 }
675
676                 protected override void OnDataSourceChanged (EventArgs e)
677                 {
678                         base.OnDataSourceChanged (e);
679                 }
680
681                 protected override void OnDisplayMemberChanged (EventArgs e)
682                 {
683                         base.OnDisplayMemberChanged (e);
684                 }
685
686                 protected virtual void OnDrawItem (DrawItemEventArgs e)
687                 {
688                         Color back_color, fore_color;
689                         
690                         if (DrawItem != null && (DrawMode == DrawMode.OwnerDrawFixed || DrawMode == DrawMode.OwnerDrawVariable)) {
691                                 DrawItem (this, e);
692                                 return;
693                         }                       
694
695                         if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) {
696                                 back_color = ThemeEngine.Current.ColorHilight;
697                                 fore_color = ThemeEngine.Current.ColorHilightText;
698                         }
699                         else {
700                                 back_color = e.BackColor;
701                                 fore_color = e.ForeColor;
702                         }
703                         
704                         e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush
705                                 (back_color), e.Bounds);
706
707                         e.Graphics.DrawString (Items[e.Index].ToString (), e.Font,
708                                 ThemeEngine.Current.ResPool.GetSolidBrush (fore_color),
709                                 e.Bounds, string_format);
710                                         
711                         if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) {
712                                 ThemeEngine.Current.CPDrawFocusRectangle (e.Graphics, e.Bounds,
713                                         fore_color, back_color);
714                         }
715                 }
716
717                 protected override void OnFontChanged (EventArgs e)
718                 {
719                         base.OnFontChanged (e);
720
721                         UpdateShowHorizontalScrollBar ();
722                         UpdateShowVerticalScrollBar ();
723                         RellocateScrollBars ();
724                         CalcClientArea ();
725                         UpdateItemInfo (false, -1, -1);
726                 }
727
728                 protected override void OnHandleCreated (EventArgs e)
729                 {
730                         base.OnHandleCreated (e);
731
732                         UpdateInternalClientRect (ClientRectangle);
733                         Controls.Add (vscrollbar_ctrl);
734                         Controls.Add (hscrollbar_ctrl);
735                         UpdateItemInfo (false, -1, -1);
736                 }
737
738                 protected override void OnHandleDestroyed (EventArgs e)
739                 {
740                         base.OnHandleDestroyed (e);
741                 }
742
743                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
744                 {
745                         if (draw_mode != DrawMode.OwnerDrawVariable)
746                                 return;
747                                 
748                         if (MeasureItem != null)
749                                 MeasureItem (this, e);
750                 }
751
752                 protected override void OnParentChanged (EventArgs e)
753                 {
754                         base.OnParentChanged (e);
755                 }
756
757                 protected override void OnResize (EventArgs e)
758                 {
759                         base.OnResize (e);
760                         UpdateInternalClientRect (ClientRectangle);
761                 }
762
763                 protected override void OnSelectedIndexChanged (EventArgs e)
764                 {
765                         base.OnSelectedIndexChanged (e);
766
767                         if (SelectedIndexChanged != null)
768                                 SelectedIndexChanged (this, e);
769                 }
770
771                 protected override void OnSelectedValueChanged (EventArgs e)
772                 {
773                         base.OnSelectedValueChanged (e);
774                 }
775
776                 public override void Refresh ()
777                 {
778                         if (draw_mode == DrawMode.OwnerDrawVariable) {
779                                 for (int i = 0; i < Items.Count; i++)  {
780                                         (Items.GetListBoxItem (i)).ItemHeight = -1;
781                                 }
782                         }
783                         
784                         base.Refresh ();
785                 }
786
787                 protected override void RefreshItem (int index)
788                 {
789                         if (index < 0 || index >= Items.Count)
790                                 throw new ArgumentOutOfRangeException ("Index of out range");
791                                 
792                         if (draw_mode == DrawMode.OwnerDrawVariable) {
793                                 (Items.GetListBoxItem (index)).ItemHeight = -1;
794                         }                       
795                 }
796
797                 protected override void SetBoundsCore (int x,  int y, int width, int height, BoundsSpecified specified)
798                 {
799                         base.SetBoundsCore (x, y, width, height, specified);
800                 }
801
802                 protected override void SetItemCore (int index,  object value)
803                 {
804                         if (index < 0 || index >= Items.Count)
805                                 return;
806
807                         Items[index] = value;
808                 }
809
810                 protected override void SetItemsCore (IList value)
811                 {
812
813                 }
814
815                 public void SetSelected (int index, bool value)
816                 {
817                         if (index < 0 || index >= Items.Count)
818                                 throw new ArgumentOutOfRangeException ("Index of out range");
819
820                         if (SelectionMode == SelectionMode.None)
821                                 throw new InvalidOperationException ();
822
823                         if (value)
824                                 SelectItem (index);
825                         else
826                                 UnSelectItem (index, true);
827                 }
828
829                 protected virtual void Sort ()
830                 {
831                         if (Items.Count == 0)
832                                 return;
833
834                         Items.Sort ();
835                         base.Refresh ();
836                 }
837
838                 public override string ToString ()
839                 {
840                         return base.ToString () + ", Items Count: " + Items.Count;
841                 }
842
843                 protected virtual void WmReflectCommand (ref Message m)
844                 {
845
846                 }
847
848                 protected override void WndProc (ref Message m)
849                 {
850                         switch ((Msg) m.Msg) {
851
852                         case Msg.WM_PAINT: {
853                                 PaintEventArgs  paint_event;
854                                 paint_event = XplatUI.PaintEventStart (Handle);
855                                 OnPaintLB (paint_event);
856                                 XplatUI.PaintEventEnd (Handle);
857                                 return;
858                         }
859
860                         case Msg.WM_ERASEBKGND:
861                                 m.Result = (IntPtr) 1;
862                                 return;
863
864                         default:
865                                 break;
866                         }
867
868                         base.WndProc (ref m);
869                 }
870
871                 #endregion Public Methods
872
873                 #region Private Methods
874
875                 internal void CalcClientArea ()
876                 {
877                         listbox_info.textdrawing_rect = listbox_info.client_rect;
878                         listbox_info.textdrawing_rect.Y += ThemeEngine.Current.DrawListBoxDecorationTop (BorderStyle);
879                         listbox_info.textdrawing_rect.X += ThemeEngine.Current.DrawListBoxDecorationLeft (BorderStyle);
880                         //BUG: Top and Left decorations
881                         listbox_info.textdrawing_rect.Height -= ThemeEngine.Current.DrawListBoxDecorationBottom (BorderStyle);
882                         listbox_info.textdrawing_rect.Width -= ThemeEngine.Current.DrawListBoxDecorationRight (BorderStyle);
883
884                         if (listbox_info.show_verticalsb)
885                                 listbox_info.textdrawing_rect.Width -= vscrollbar_ctrl.Width;
886
887                         if (listbox_info.show_horizontalsb)
888                                 listbox_info.textdrawing_rect.Height -= hscrollbar_ctrl.Height;
889
890                         if (DrawMode == DrawMode.OwnerDrawVariable) {                           
891                                 int height = 0;
892                                 
893                                 listbox_info.page_size = 0;
894                                 for (int i = 0; i < Items.Count; i++) {
895                                         height += GetItemHeight (i);
896                                         if (height > listbox_info.textdrawing_rect.Height)
897                                                 break;
898                                                 
899                                         listbox_info.page_size++;                                       
900                                 }
901                                                                 
902                         } else {                        
903                                 listbox_info.page_size = listbox_info.textdrawing_rect.Height / listbox_info.item_height;
904                         }
905
906                         if (listbox_info.page_size == 0) {
907                                 listbox_info.page_size = 1;
908                         }
909
910                         /* Adjust size to visible the maxim number of displayable items */
911                         if (IntegralHeight == true) {
912
913                                 // From MS Docs: The integral height is based on the height of the ListBox, rather than
914                                 // the client area height. As a result, when the IntegralHeight property is set true,
915                                 // items can still be partially shown if scroll bars are displayed.
916
917                                 int remaining =  (listbox_info.client_rect.Height -
918                                         ThemeEngine.Current.DrawListBoxDecorationBottom (BorderStyle) -
919                                         ThemeEngine.Current.DrawListBoxDecorationBottom (BorderStyle)) %
920                                         listbox_info.item_height;
921
922                                 if (remaining > 0) {
923                                         listbox_info.client_rect.Height -= remaining;
924                                         CalcClientArea ();
925                                         RellocateScrollBars ();
926                                         base.Refresh ();
927                                 }
928                         }
929                 }
930
931                 internal void Draw (Rectangle clip)
932                 {       
933                         if (LBoxInfo.textdrawing_rect.Contains (clip) == false) {
934                                 // IntegralHeight has effect, we also have to paint the unused area
935                                 if (ClientRectangle.Height > listbox_info.client_rect.Height) {
936                                         Region area = new Region (ClientRectangle);
937                                         area.Exclude (listbox_info.client_rect);
938
939                                         DeviceContext.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (Parent.BackColor),
940                                                 area.GetBounds (DeviceContext));
941                                 }
942
943                                 DeviceContext.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), LBoxInfo.textdrawing_rect);                         
944                         }                                       
945
946                         if (Items.Count > 0) {
947                                 Rectangle item_rect;
948                                 DrawItemState state = DrawItemState.None;
949
950                                 for (int i = LBoxInfo.top_item; i <= LBoxInfo.last_item; i++) {
951                                         item_rect = GetItemDisplayRectangle (i, LBoxInfo.top_item);
952
953                                         if (clip.IntersectsWith (item_rect) == false)
954                                                 continue;
955
956                                         /* Draw item */
957                                         state = DrawItemState.None;
958
959                                         if ((Items.GetListBoxItem (i)).Selected) {
960                                                 state |= DrawItemState.Selected;
961                                         }
962                                         
963                                         if (has_focus == true && focused_item == i)
964                                                 state |= DrawItemState.Focus;
965
966                                         OnDrawItem (new DrawItemEventArgs (DeviceContext, Font, item_rect,
967                                                 i, state, ForeColor, BackColor));
968                                 }
969                         }                       
970                         
971                         ThemeEngine.Current.DrawListBoxDecorations (DeviceContext, this);
972                 }
973
974                 // Converts a GetItemRectangle to a one that we can display
975                 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
976                 {
977                         Rectangle item_rect;
978                         Rectangle first_item_rect = GetItemRectangle (first_displayble);
979                         item_rect = GetItemRectangle (index);
980                         item_rect.X -= first_item_rect.X;
981                         item_rect.Y -= first_item_rect.Y;
982
983                         item_rect.Y += ThemeEngine.Current.DrawListBoxDecorationTop (BorderStyle);
984                         item_rect.X += ThemeEngine.Current.DrawListBoxDecorationLeft (BorderStyle);
985                         item_rect.Width -= ThemeEngine.Current.DrawListBoxDecorationRight (BorderStyle);
986
987                         return item_rect;
988                 }
989
990                 // Value Changed
991                 private void HorizontalScrollEvent (object sender, EventArgs e)
992                 {
993                         LBoxInfo.top_item = listbox_info.page_size * hscrollbar_ctrl.Value;
994                         LBoxInfo.last_item = LastVisibleItem ();
995                         base.Refresh ();
996                 }
997
998                 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
999                 // has screen coordinates
1000                 internal int IndexFromPointDisplayRectangle (int x, int y)
1001                 {
1002                         for (int i = LBoxInfo.top_item; i < LBoxInfo.last_item; i++) {
1003                                 if (GetItemDisplayRectangle (i, LBoxInfo.top_item).Contains (x, y) == true)
1004                                         return i;
1005                         }
1006
1007                         return -1;
1008                 }
1009
1010                 private int LastVisibleItem ()
1011                 {
1012                         Rectangle item_rect;
1013                         int top_y = LBoxInfo.textdrawing_rect.Y + LBoxInfo.textdrawing_rect.Height;
1014                         int i = 0;
1015
1016                         if (LBoxInfo.top_item >= Items.Count)
1017                                 return LBoxInfo.top_item;
1018
1019                         for (i = LBoxInfo.top_item; i < Items.Count; i++) {
1020
1021                                 item_rect = GetItemDisplayRectangle (i, LBoxInfo.top_item);
1022                                 if (MultiColumn) {
1023
1024                                         if (item_rect.X > LBoxInfo.textdrawing_rect.Width)
1025                                                 return i - 1;
1026                                 }
1027                                 else {
1028                                         if (IntegralHeight) {
1029                                                 if (item_rect.Y + item_rect.Height > top_y) {
1030                                                         return i - 1;
1031                                                 }
1032                                         }
1033                                         else {
1034                                                 if (item_rect.Y + item_rect.Height > top_y)
1035                                                         return i - 1;
1036                                         }
1037                                 }
1038                         }
1039                         return i - 1;
1040                 }
1041
1042                 private void UpdatedTopItem ()
1043                 {
1044                         if (multicolumn) {
1045                                 int col = (LBoxInfo.top_item / LBoxInfo.page_size);
1046                                 hscrollbar_ctrl.Value = col;
1047                         }                               
1048                         else {
1049                                 if (LBoxInfo.top_item > vscrollbar_ctrl.Maximum)
1050                                         vscrollbar_ctrl.Value = vscrollbar_ctrl.Maximum;
1051                                 else
1052                                         vscrollbar_ctrl.Value = LBoxInfo.top_item;
1053                         }
1054                 }
1055                 
1056                 // Navigates to the indicated item and returns the new item
1057                 private int NavigateItemVisually (ItemNavigation navigation)
1058                 {                       
1059                         int page_size, columns, selected_index = -1;
1060
1061                         if (multicolumn) {
1062                                 columns = LBoxInfo.textdrawing_rect.Width / ColumnWidthInternal; 
1063                                 page_size = columns * LBoxInfo.page_size;
1064                                 if (page_size == 0) {
1065                                         page_size = LBoxInfo.page_size;
1066                                 }
1067                         } else {
1068                                 page_size = LBoxInfo.page_size; 
1069                         }
1070
1071                         switch (navigation) {
1072
1073                         case ItemNavigation.PreviousColumn: {
1074                                 if (focused_item - LBoxInfo.page_size < 0) {
1075                                         return -1;
1076                                 }
1077
1078                                 if (focused_item - LBoxInfo.page_size < LBoxInfo.top_item) {
1079                                         LBoxInfo.top_item = focused_item - LBoxInfo.page_size;
1080                                         UpdatedTopItem ();
1081                                 }
1082                                         
1083                                 selected_index = focused_item - LBoxInfo.page_size;
1084                                 break;
1085                         }
1086                         
1087                         case ItemNavigation.NextColumn: {
1088                                 if (focused_item + LBoxInfo.page_size >= Items.Count) {
1089                                         break;
1090                                 }
1091
1092                                 if (focused_item + LBoxInfo.page_size > LBoxInfo.last_item) {
1093                                         LBoxInfo.top_item = focused_item;
1094                                         UpdatedTopItem ();
1095                                 }
1096                                         
1097                                 selected_index = focused_item + LBoxInfo.page_size;                                     
1098                                 break;
1099                         }
1100
1101                         case ItemNavigation.First: {
1102                                 LBoxInfo.top_item = 0;
1103                                 selected_index  = 0;
1104                                 UpdatedTopItem ();
1105                                 break;
1106                         }
1107
1108                         case ItemNavigation.Last: {
1109
1110                                 if (Items.Count < LBoxInfo.page_size) {
1111                                         LBoxInfo.top_item = 0;
1112                                         selected_index  = Items.Count - 1;
1113                                         UpdatedTopItem ();
1114                                 } else {
1115                                         LBoxInfo.top_item = Items.Count - LBoxInfo.page_size;
1116                                         selected_index  = Items.Count - 1;
1117                                         UpdatedTopItem ();
1118                                 }
1119                                 break;
1120                         }
1121
1122                         case ItemNavigation.Next: {
1123                                 if (focused_item + 1 < Items.Count) {   
1124                                         if (focused_item + 1 > LBoxInfo.last_item) {
1125                                                 LBoxInfo.top_item++;
1126                                                 UpdatedTopItem ();                                              
1127                                         }
1128                                         selected_index = focused_item + 1;
1129                                 }
1130                                 break;
1131                         }
1132
1133                         case ItemNavigation.Previous: {
1134                                 if (focused_item > 0) {                                         
1135                                         if (focused_item - 1 < LBoxInfo.top_item) {                                                     
1136                                                 LBoxInfo.top_item--;
1137                                                 UpdatedTopItem ();
1138                                         }
1139                                         selected_index = focused_item - 1;
1140                                 }                                       
1141                                 break;
1142                         }
1143
1144                         case ItemNavigation.NextPage: {
1145                                 if (Items.Count < page_size) {
1146                                         NavigateItemVisually (ItemNavigation.Last);
1147                                         break;
1148                                 }
1149
1150                                 if (focused_item + page_size - 1 >= Items.Count) {
1151                                         LBoxInfo.top_item = Items.Count - page_size;
1152                                         UpdatedTopItem ();
1153                                         selected_index = Items.Count - 1;                                               
1154                                 }
1155                                 else {
1156                                         if (focused_item + page_size - 1  > LBoxInfo.last_item) {
1157                                                 LBoxInfo.top_item = focused_item;
1158                                                 UpdatedTopItem ();
1159                                         }
1160                                         
1161                                         selected_index = focused_item + page_size - 1;                                          
1162                                 }
1163                                         
1164                                 break;
1165                         }                       
1166
1167                         case ItemNavigation.PreviousPage: {
1168                                         
1169                                 if (focused_item - (LBoxInfo.page_size - 1) <= 0) {
1170                                                                                                                                                 
1171                                         LBoxInfo.top_item = 0;
1172                                         vscrollbar_ctrl.Value = LBoxInfo.top_item;
1173                                         SelectedIndex = 0;                                      
1174                                 }
1175                                 else { 
1176                                         if (focused_item - (LBoxInfo.page_size - 1)  < LBoxInfo.top_item) {
1177                                                 LBoxInfo.top_item = focused_item - (LBoxInfo.page_size - 1);
1178                                                 vscrollbar_ctrl.Value = LBoxInfo.top_item;
1179                                         }
1180                                         
1181                                         selected_index = focused_item - (LBoxInfo.page_size - 1);
1182                                 }
1183                                         
1184                                 break;
1185                         }               
1186                         default:
1187                                 break;                          
1188                         }
1189                         
1190                         return selected_index;
1191                 }
1192                 
1193                 private void OnGotFocus (object sender, EventArgs e)                    
1194                 {                       
1195                         has_focus = true;                       
1196                         
1197                         if (focused_item != -1) {
1198                                 Rectangle invalidate = GetItemDisplayRectangle (focused_item, LBoxInfo.top_item);
1199                                 Invalidate (invalidate);
1200                         }
1201                 }               
1202                 
1203                 private void OnLostFocus (object sender, EventArgs e)                   
1204                 {                       
1205                         has_focus = false;
1206                         
1207                         if (focused_item != -1) {
1208                                 Rectangle invalidate = GetItemDisplayRectangle (focused_item, LBoxInfo.top_item);
1209                                 Invalidate (invalidate);
1210                         }                       
1211                 }               
1212
1213                 private void OnKeyDownLB (object sender, KeyEventArgs e)
1214                 {                                       
1215                         int new_item = -1;
1216
1217                         switch (e.KeyCode) {
1218                                 
1219                                 case Keys.ControlKey:
1220                                         ctrl_pressed = true;
1221                                         break;
1222                                         
1223                                 case Keys.ShiftKey:
1224                                         shift_pressed = true;
1225                                         break;
1226                                         
1227                                 case Keys.Home:
1228                                         new_item = NavigateItemVisually (ItemNavigation.First);
1229                                         break;  
1230
1231                                 case Keys.End:
1232                                         new_item = NavigateItemVisually (ItemNavigation.Last);
1233                                         break;  
1234 \r
1235                                 case Keys.Up:
1236                                         new_item = NavigateItemVisually (ItemNavigation.Previous);
1237                                         break;                          
1238         
1239                                 case Keys.Down:                         
1240                                         new_item = NavigateItemVisually (ItemNavigation.Next);
1241                                         break;
1242                                 
1243                                 case Keys.PageUp:
1244                                         new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1245                                         break;                          
1246         
1247                                 case Keys.PageDown:                             
1248                                         new_item = NavigateItemVisually (ItemNavigation.NextPage);
1249                                         break;
1250
1251                                 case Keys.Right:
1252                                         if (multicolumn == true) {
1253                                                 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1254                                         }
1255                                         break;                          
1256         
1257                                 case Keys.Left:                 
1258                                         if (multicolumn == true) {      
1259                                                 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1260                                         }
1261                                         break;
1262                                         
1263                                 case Keys.Space:
1264                                         if (selection_mode == SelectionMode.MultiSimple) {
1265                                                 SelectedItemFromNavigation (focused_item);
1266                                         }
1267                                         break;
1268                                 
1269
1270                                 default:
1271                                         break;
1272                                 }
1273                                 
1274                                 if (new_item != -1) {
1275                                         SetFocusedItem (new_item);
1276                                 }
1277                                 
1278                                 if (new_item != -1) {                                   
1279                                         if (selection_mode != SelectionMode.MultiSimple && selection_mode != SelectionMode.None) {
1280                                                 SelectedItemFromNavigation (new_item);
1281                                         }
1282                                 }
1283                 }
1284                 
1285                 private void OnKeyUpLB (object sender, KeyEventArgs e)                  
1286                 {
1287                         switch (e.KeyCode) {
1288                                 case Keys.ControlKey:
1289                                         ctrl_pressed = false;
1290                                         break;
1291                                 case Keys.ShiftKey:
1292                                         shift_pressed = false;
1293                                         break;
1294                                 default: 
1295                                         break;
1296                         }
1297                 }               
1298
1299                 internal virtual void OnMouseDownLB (object sender, MouseEventArgs e)
1300                 {
1301                         int index = IndexFromPointDisplayRectangle (e.X, e.Y);
1302                         
1303                         if (index != -1) {
1304                                 SelectedItemFromNavigation (index);
1305                                 SetFocusedItem (index);
1306                         }
1307                 }
1308
1309                 private void OnPaintLB (PaintEventArgs pevent)
1310                 {
1311                         if (Width <= 0 || Height <=  0 || Visible == false || suspend_ctrlupdate == true)
1312                                 return;
1313
1314                         /* Copies memory drawing buffer to screen*/
1315                         Draw (pevent.ClipRectangle);
1316                         pevent.Graphics.DrawImage (ImageBuffer, pevent.ClipRectangle, pevent.ClipRectangle, GraphicsUnit.Pixel);
1317
1318                         if (Paint != null)
1319                                 Paint (this, pevent);
1320                 }
1321
1322                 internal void RellocateScrollBars ()
1323                 {
1324                         if (listbox_info.show_verticalsb) {
1325
1326                                 vscrollbar_ctrl.Size = new Size (vscrollbar_ctrl.Width,
1327                                         listbox_info.client_rect.Height - ThemeEngine.Current.DrawListBoxDecorationTop (BorderStyle) -
1328                                         ThemeEngine.Current.DrawListBoxDecorationBottom (BorderStyle));
1329
1330                                 vscrollbar_ctrl.Location = new Point (listbox_info.client_rect.Width - vscrollbar_ctrl.Width
1331                                         - ThemeEngine.Current.DrawListBoxDecorationRight (BorderStyle),
1332                                         ThemeEngine.Current.DrawListBoxDecorationTop (BorderStyle));
1333
1334                         }
1335
1336                         if (listbox_info.show_horizontalsb) {
1337
1338                                 int width;
1339
1340                                 width = listbox_info.client_rect.Width - (ThemeEngine.Current.DrawListBoxDecorationLeft (BorderStyle) + ThemeEngine.Current.DrawListBoxDecorationRight (BorderStyle));
1341
1342                                 if (listbox_info.show_verticalsb)
1343                                         width -= vscrollbar_ctrl.Width;
1344
1345                                 hscrollbar_ctrl.Size = new Size (width, hscrollbar_ctrl.Height);
1346
1347                                 hscrollbar_ctrl.Location = new Point (ThemeEngine.Current.DrawListBoxDecorationLeft (BorderStyle),
1348                                         listbox_info.client_rect.Height - hscrollbar_ctrl.Height
1349                                         - ThemeEngine.Current.DrawListBoxDecorationTop (BorderStyle));
1350                         }
1351
1352                         CalcClientArea ();
1353                 }
1354
1355                 // Add an item in the Selection array and marks it visually as selected
1356                 private void SelectItem (int index)
1357                 {
1358                         if (index == -1)
1359                                 return;
1360
1361                         Rectangle invalidate = GetItemDisplayRectangle (index, LBoxInfo.top_item);
1362                         (Items.GetListBoxItem (index)).Selected = true;
1363                         selected_indices.AddIndex (index);
1364                         selected_items.AddObject (Items[index]);
1365
1366                         if (ClientRectangle.Contains (invalidate))
1367                                 Invalidate (invalidate);
1368
1369                 }               
1370                 
1371                 // An item navigation operation (mouse or keyboard) has caused to select a new item
1372                 private void SelectedItemFromNavigation (int index)
1373                 {
1374                         switch (SelectionMode) {
1375                                 case SelectionMode.None: // Do nothing
1376                                         break;
1377                                 case SelectionMode.One: {
1378                                         SelectedIndex = index;
1379                                         break;
1380                                 }
1381                                 case SelectionMode.MultiSimple: {
1382                                         if (selected_index == -1) {
1383                                                 SelectedIndex = index;
1384                                         } else {
1385
1386                                                 if ((Items.GetListBoxItem (index)).Selected) // BUG: index or selected_index?
1387                                                         UnSelectItem (index, true);
1388                                                 else {
1389                                                         SelectItem (index);
1390                                                         OnSelectedIndexChanged  (new EventArgs ());
1391                                                 }
1392                                         }
1393                                         break;
1394                                 }
1395                                 
1396                                 case SelectionMode.MultiExtended: {
1397                                         if (selected_index == -1) {
1398                                                 SelectedIndex = index;
1399                                         } else {
1400
1401                                                 if (ctrl_pressed == false && shift_pressed == false) {
1402                                                         ClearSelected ();
1403                                                 }
1404                                                 
1405                                                 if (shift_pressed == true) {
1406                                                         ShiftSelection (index);
1407                                                 } else { // ctrl_pressed or single item
1408                                                         SelectItem (index);
1409                                                 }
1410                                                 
1411                                                 OnSelectedIndexChanged  (new EventArgs ());
1412                                         }
1413                                         break;
1414                                 }                               
1415                                 
1416                                 default:
1417                                         break;
1418                         }                       
1419                 }
1420                 
1421                 private void ShiftSelection (int index)
1422                 {
1423                         int shorter_item = -1, dist = Items.Count + 1, cur_dist;
1424                         
1425                         foreach (int idx in selected_indices) {
1426                                 if (idx > index) {
1427                                         cur_dist = idx - index;
1428                                 }
1429                                 else {
1430                                         cur_dist = index - idx;                                 
1431                                 }
1432                                                 
1433                                 if (cur_dist < dist) {
1434                                         dist = cur_dist;
1435                                         shorter_item = idx;
1436                                 }
1437                         }
1438                         
1439                         if (shorter_item != -1) {
1440                                 int start, end;
1441                                 
1442                                 if (shorter_item > index) {
1443                                         start = index;
1444                                         end = shorter_item;
1445                                 } else {
1446                                         start = shorter_item;
1447                                         end = index;
1448                                 }
1449                                 
1450                                 ClearSelected ();
1451                                 for (int idx = start; idx <= end; idx++) {
1452                                         SelectItem (idx);       
1453                                 }
1454                         }
1455                 }
1456                 
1457                 void SetFocusedItem (int index)
1458                 {                       
1459                         Rectangle invalidate;
1460                         int prev = focused_item;                        
1461                         
1462                         focused_item = index;
1463                         
1464                         if (has_focus == false)
1465                                 return;
1466
1467                         if (prev != -1) { // Invalidates previous item
1468                                 invalidate = GetItemDisplayRectangle (prev, LBoxInfo.top_item);
1469                                 Invalidate (invalidate);
1470                         }
1471                         
1472                         if (index != -1) {
1473                                 invalidate = GetItemDisplayRectangle (index, LBoxInfo.top_item);
1474                                 Invalidate (invalidate);
1475                         }
1476                 }
1477
1478                 // Removes an item in the Selection array and marks it visually as unselected
1479                 private void UnSelectItem (int index, bool remove)
1480                 {
1481                         if (index == -1)
1482                                 return;
1483
1484                         Rectangle invalidate = GetItemDisplayRectangle (index, LBoxInfo.top_item);
1485                         (Items.GetListBoxItem (index)).Selected = false;
1486
1487                         if (remove) {
1488                                 selected_indices.RemoveIndex (index);
1489                                 selected_items.RemoveObject (Items[index]);
1490                         }
1491
1492
1493                         if (ClientRectangle.Contains (invalidate))
1494                                 Invalidate (invalidate);
1495                 }
1496
1497                 private void UpdateFormatString ()
1498                 {
1499                         Console.WriteLine ("UpdateFormatString {0}", RightToLeft);
1500                         
1501                         if (RightToLeft == RightToLeft.Yes)
1502                                 string_format.Alignment = StringAlignment.Far;                          
1503                         else
1504                                 string_format.Alignment = StringAlignment.Near;                         
1505
1506                         if (UseTabStops)
1507                                 string_format.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
1508                 }
1509
1510                 // Updates the scrollbar's position with the new items and inside area
1511                 internal virtual void UpdateItemInfo (bool adding, int first, int last)
1512                 {
1513                         if (!IsHandleCreated || suspend_ctrlupdate == true)
1514                                 return;
1515
1516                         UpdateShowVerticalScrollBar ();
1517
1518                         if (listbox_info.show_verticalsb && Items.Count > listbox_info.page_size)
1519                                 if (vscrollbar_ctrl.Enabled)
1520                                         vscrollbar_ctrl.Maximum = Items.Count - listbox_info.page_size;
1521
1522                         if (listbox_info.show_horizontalsb) {
1523                                 if (MultiColumn) {
1524                                         int fullpage = (listbox_info.page_size * (listbox_info.client_rect.Width / ColumnWidthInternal));
1525
1526                                         if (hscrollbar_ctrl.Enabled && listbox_info.page_size > 0)
1527                                                 hscrollbar_ctrl.Maximum  = Math.Max (0, 1 + ((Items.Count - fullpage) / listbox_info.page_size));
1528                                 }
1529                         }
1530
1531                         if (MultiColumn == false) {
1532                                 /* Calc the longest items for non multicolumn listboxes */
1533                                 if ((first == -1 && last == -1) || (adding == false)) {
1534
1535                                         SizeF size;
1536                                         for (int i = 0; i < Items.Count; i++) {
1537                                                 size = DeviceContext.MeasureString (Items[i].ToString(), Font);
1538
1539                                                 if ((int) size.Width > listbox_info.max_itemwidth)
1540                                                         listbox_info.max_itemwidth = (int) size.Width;
1541                                         }
1542                                 }
1543                                 else {
1544                                         if (adding) {
1545
1546                                                 SizeF size;
1547                                                 for (int i = first; i < last + 1; i++) {
1548                                                         size = DeviceContext.MeasureString (Items[i].ToString(), Font);
1549
1550                                                         if ((int) size.Width > listbox_info.max_itemwidth)
1551                                                                 listbox_info.max_itemwidth = (int) size.Width;
1552                                                 }
1553                                         }
1554                                 }
1555                         }
1556
1557                         if (sorted) 
1558                                 Sort ();
1559
1560                         SelectedItems.ReCreate ();
1561                         SelectedIndices.ReCreate ();
1562                         LBoxInfo.last_item = LastVisibleItem ();
1563
1564                         UpdateShowHorizontalScrollBar ();
1565                         base.Refresh ();
1566                 }
1567
1568                 private void UpdateInternalClientRect (Rectangle client_rectangle)
1569                 {
1570                         listbox_info.client_rect = client_rectangle;
1571                         UpdateShowHorizontalScrollBar ();
1572                         UpdateShowVerticalScrollBar ();
1573                         RellocateScrollBars ();
1574                         UpdateItemInfo (false, -1, -1);
1575                 }
1576
1577                 /* Determines if the horizontal scrollbar has to be displyed */
1578                 private void UpdateShowHorizontalScrollBar ()
1579                 {
1580                         bool show = false;
1581                         bool enabled = true;
1582
1583                         if (MultiColumn) {  /* Horizontal scrollbar is always shown in Multicolum mode */
1584
1585                                 /* Is it really need it */
1586                                 int page_size = listbox_info.client_rect.Height / listbox_info.item_height;
1587                                 int fullpage = (page_size * (listbox_info.textdrawing_rect.Height / ColumnWidthInternal));
1588
1589                                 if (Items.Count > fullpage) {
1590                                         if (IntegralHeight == false)
1591                                                 show = true;
1592                                 }
1593                                 else { /* Acording to MS Documentation ScrollAlwaysVisible only affects Horizontal scrollbars but
1594                                           this is not true for MultiColumn listboxes */
1595                                         if (ScrollAlwaysVisible == true) {
1596                                                 enabled = false;
1597                                                 show = true;
1598                                         }
1599                                 }
1600
1601                         } else { /* If large item*/
1602
1603                                 if (listbox_info.max_itemwidth > listbox_info.client_rect.Width && HorizontalScrollbar) {
1604                                         show = true;
1605                                         hscrollbar_ctrl.Maximum = listbox_info.max_itemwidth;
1606                                 }
1607                         }
1608
1609                         if (hscrollbar_ctrl.Enabled != enabled)
1610                                 hscrollbar_ctrl.Enabled = enabled;
1611
1612                         if (listbox_info.show_horizontalsb == show)
1613                                 return;
1614
1615                         listbox_info.show_horizontalsb = show;
1616                         hscrollbar_ctrl.Visible = show;
1617
1618                         if (show == true) {
1619                                 RellocateScrollBars ();
1620                         }
1621
1622                         CalcClientArea ();
1623                 }
1624
1625                 /* Determines if the vertical scrollbar has to be displyed */
1626                 private void UpdateShowVerticalScrollBar ()
1627                 {
1628                         bool show = false;
1629                         bool enabled = true;
1630
1631                         if (!MultiColumn) {  /* Vertical scrollbar is never shown in Multicolum mode */
1632                                 if (Items.Count > listbox_info.page_size) {
1633                                         show = true;
1634                                 }
1635                                 else
1636                                         if (ScrollAlwaysVisible) {
1637                                                 show = true;
1638                                                 enabled = false;
1639                                         }
1640                         }
1641
1642                         if (vscrollbar_ctrl.Enabled != enabled)
1643                                 vscrollbar_ctrl.Enabled = enabled;
1644
1645                         if (listbox_info.show_verticalsb == show)
1646                                 return;
1647
1648                         listbox_info.show_verticalsb = show;
1649                         vscrollbar_ctrl.Visible = show;
1650
1651                         if (show == true) {
1652                                 if (vscrollbar_ctrl.Enabled)
1653                                         vscrollbar_ctrl.Maximum = Items.Count - listbox_info.page_size;
1654
1655                                 RellocateScrollBars ();
1656                         }
1657
1658                         CalcClientArea ();
1659                 }
1660
1661                 // Value Changed
1662                 private void VerticalScrollEvent (object sender, EventArgs e)
1663                 {
1664                         LBoxInfo.top_item = /*listbox_info.page_size + */ vscrollbar_ctrl.Value;
1665                         LBoxInfo.last_item = LastVisibleItem ();
1666
1667                         base.Refresh ();
1668                 }
1669
1670                 #endregion Private Methods
1671
1672                 /*
1673                         ListBox.ObjectCollection
1674                 */
1675                 public class ObjectCollection : IList, ICollection, IEnumerable
1676                 {
1677                         // Compare objects
1678                         internal class ListObjectComparer : IComparer\r
1679                         {\r
1680                                 private ListBox owner;\r
1681                         \r
1682                                 public ListObjectComparer (ListBox owner)\r
1683                                 {\r
1684                                         this.owner = owner;\r
1685                                 }\r
1686                                 \r
1687                                 public int Compare (object a, object b)\r
1688                                 {\r
1689                                         string str1 = a.ToString ();
1690                                         string str2 = b.ToString ();                                    \r
1691                                         return str1.CompareTo (str2);\r
1692                                 }\r
1693                         }
1694
1695                         // Compare ListItem
1696                         internal class ListItemComparer : IComparer\r
1697                         {\r
1698                                 private ListBox owner;\r
1699                         \r
1700                                 public ListItemComparer (ListBox owner)\r
1701                                 {\r
1702                                         this.owner = owner;\r
1703                                 }\r
1704                                 \r
1705                                 public int Compare (object a, object b)\r
1706                                 {\r
1707                                         int index1 = ((ListBox.ListBoxItem) (a)).Index;
1708                                         int index2 = ((ListBox.ListBoxItem) (b)).Index;
1709                                         string str1 = owner.Items[index1].ToString ();
1710                                         string str2 = owner.Items[index2].ToString ();                                  \r
1711                                         return str1.CompareTo (str2);                                   \r
1712                                 }\r
1713                         }
1714
1715                         private ListBox owner;
1716                         internal ArrayList object_items = new ArrayList ();
1717                         internal ArrayList listbox_items = new ArrayList ();
1718
1719                         public ObjectCollection (ListBox owner)
1720                         {
1721                                 this.owner = owner;
1722                         }
1723
1724                         public ObjectCollection (ListBox owner, object[] obj)
1725                         {
1726                                 this.owner = owner;
1727                                 AddRange (obj);
1728                         }
1729
1730                         public ObjectCollection (ListBox owner,  ObjectCollection obj)
1731                         {
1732                                 this.owner = owner;
1733                                 AddRange (obj);
1734                         }
1735
1736                         #region Public Properties
1737                         public virtual int Count {
1738                                 get { return object_items.Count; }
1739                         }
1740
1741                         public virtual bool IsReadOnly {
1742                                 get { return false; }
1743                         }
1744
1745                         public virtual object this [int index] {
1746                                 get {
1747                                         if (index < 0 || index >= Count)
1748                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1749
1750                                         return object_items[index];
1751                                 }
1752                                 set {
1753                                         if (index < 0 || index >= Count)
1754                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1755
1756                                         object_items[index] = value;
1757                                 }
1758                         }
1759
1760                         bool ICollection.IsSynchronized {
1761                                 get { return false; }
1762                         }
1763
1764                         object ICollection.SyncRoot {
1765                                 get { return this; }
1766                         }
1767
1768                         bool IList.IsFixedSize {
1769                                 get { return false; }
1770                         }
1771
1772                         #endregion Public Properties
1773
1774                         #region Public Methods
1775                         public int Add (object item)
1776                         {
1777                                 int idx;
1778
1779                                 idx = AddItem (item);
1780                                 owner.UpdateItemInfo (true, idx, idx);
1781                                 return idx;
1782                         }
1783
1784                         public void AddRange (object[] items)
1785                         {
1786                                 int cnt = Count;
1787
1788                                 foreach (object mi in items)
1789                                         AddItem (mi);
1790
1791                                 owner.UpdateItemInfo (true, cnt, Count);
1792                         }
1793
1794                         public void AddRange (ObjectCollection col)
1795                         {
1796                                 int cnt = Count;
1797
1798                                 foreach (object mi in col)
1799                                         AddItem (mi);
1800
1801                                 owner.UpdateItemInfo (true, cnt, Count);
1802                         }
1803
1804                         public virtual void Clear ()
1805                         {
1806                                 object_items.Clear ();
1807                                 listbox_items.Clear ();
1808                                 owner.UpdateItemInfo (false, -1, -1);
1809                         }
1810                         public virtual bool Contains (object obj)
1811                         {
1812                                 return object_items.Contains (obj);
1813                         }
1814
1815                         public void CopyTo (object[] dest, int arrayIndex)
1816                         {
1817                                 object_items.CopyTo (dest, arrayIndex);
1818                         }
1819
1820                         void ICollection.CopyTo (Array dest, int index)
1821                         {
1822                                 object_items.CopyTo (dest, index);
1823                         }
1824
1825                         public virtual IEnumerator GetEnumerator ()
1826                         {
1827                                 return object_items.GetEnumerator ();
1828                         }
1829
1830                         int IList.Add (object item)
1831                         {
1832                                 return Add (item);
1833                         }
1834
1835                         public virtual int IndexOf (object value)
1836                         {
1837                                 return object_items.IndexOf (value);
1838                         }
1839
1840                         public virtual void Insert (int index,  object item)
1841                         {
1842                                 throw new NotImplementedException ();
1843                         }
1844
1845                         public virtual void Remove (object value)
1846                         {
1847                                 RemoveAt (IndexOf (value));
1848                                 owner.UpdateItemInfo (false, -1, -1);
1849                         }
1850
1851                         public virtual void RemoveAt (int index)
1852                         {
1853                                 if (index < 0 || index >= Count)
1854                                         throw new ArgumentOutOfRangeException ("Index of out range");
1855
1856                                 object_items.RemoveAt (index);
1857                                 listbox_items.RemoveAt (index);
1858                                 owner.UpdateItemInfo (false, -1, -1);
1859                         }
1860                         #endregion Public Methods
1861
1862                         #region Private Methods
1863                         private int AddItem (object item)
1864                         {
1865                                 int cnt = object_items.Count;
1866                                 object_items.Add (item);
1867                                 listbox_items.Add (new ListBox.ListBoxItem (cnt));
1868                                 return cnt;
1869                         }
1870
1871                         internal ListBox.ListBoxItem GetListBoxItem (int index)
1872                         {
1873                                 if (index < 0 || index >= Count)
1874                                         throw new ArgumentOutOfRangeException ("Index of out range");
1875
1876                                 return (ListBox.ListBoxItem) listbox_items[index];
1877                         }
1878
1879                         internal void SetListBoxItem (ListBox.ListBoxItem item, int index)
1880                         {
1881                                 if (index < 0 || index >= Count)
1882                                         throw new ArgumentOutOfRangeException ("Index of out range");
1883
1884                                 listbox_items[index] = item;
1885                         }
1886
1887                         internal void Sort ()
1888                         {
1889                                 /* Keep this order */
1890                                 listbox_items.Sort (new ListItemComparer (owner));
1891                                 object_items.Sort (new ListObjectComparer (owner));
1892
1893                                 for (int i = 0; i < listbox_items.Count; i++) {
1894                                         ListBox.ListBoxItem item = GetListBoxItem (i);
1895                                         item.Index = i;
1896                                 }
1897                         }
1898
1899                         #endregion Private Methods
1900                 }
1901
1902                 /*
1903                         ListBox.SelectedIndexCollection
1904                 */
1905                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
1906                 {
1907                         private ListBox owner;
1908                         private ArrayList indices = new ArrayList ();
1909
1910                         public SelectedIndexCollection (ListBox owner)
1911                         {
1912                                 this.owner = owner;
1913                         }
1914
1915                         #region Public Properties
1916                         public virtual int Count {
1917                                 get { return indices.Count; }
1918                         }
1919
1920                         public virtual bool IsReadOnly {
1921                                 get { return true; }
1922                         }
1923
1924                         public int this [int index] {
1925                                 get {
1926                                         if (index < 0 || index >= Count)
1927                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1928
1929                                         return (int) indices[index];
1930                                 }
1931                         }
1932
1933                         bool ICollection.IsSynchronized {
1934                                 get { return true; }
1935                         }
1936
1937                         bool IList.IsFixedSize{
1938                                 get { return true; }
1939                         }
1940
1941                         object ICollection.SyncRoot {
1942                                 get { return this; }
1943                         }
1944
1945                         #endregion Public Properties
1946
1947                         #region Public Methods
1948                         public bool Contains (int selectedIndex)
1949                         {
1950                                 return indices.Contains (selectedIndex);
1951                         }
1952
1953                         public virtual void CopyTo (Array dest, int index)
1954                         {
1955                                 indices.CopyTo (dest, index);
1956                         }
1957
1958                         public virtual IEnumerator GetEnumerator ()
1959                         {
1960                                 return indices.GetEnumerator ();
1961                         }
1962
1963                         int IList.Add (object obj)
1964                         {
1965                                 throw new NotSupportedException ();
1966                         }
1967
1968                         void IList.Clear ()
1969                         {
1970                                 throw new NotSupportedException ();
1971                         }
1972
1973                         bool IList.Contains (object selectedIndex)
1974                         {
1975                                 return Contains ((int)selectedIndex);
1976                         }
1977
1978                         int IList.IndexOf (object selectedIndex)
1979                         {
1980                                 return IndexOf ((int) selectedIndex);
1981                         }
1982
1983                         void IList.Insert (int index, object value)
1984                         {
1985                                 throw new NotSupportedException ();
1986                         }
1987
1988                         void IList.Remove (object value)
1989                         {
1990                                 throw new NotSupportedException ();
1991                         }
1992
1993                         void IList.RemoveAt (int index)
1994                         {
1995                                 throw new NotSupportedException ();
1996                         }
1997
1998                         object IList.this[int index]{
1999                                 get {return indices[index]; }
2000                                 set {throw new NotImplementedException (); }
2001                         }
2002
2003                         public int IndexOf (int selectedIndex)
2004                         {
2005                                 return indices.IndexOf (selectedIndex);
2006                         }
2007                         #endregion Public Methods
2008
2009                         #region Private Methods
2010
2011                         internal void AddIndex (int index)
2012                         {
2013                                 indices.Add (index);
2014                         }
2015
2016                         internal void ClearIndices ()
2017                         {
2018                                 indices.Clear ();
2019                         }
2020
2021                         internal void RemoveIndex (int index)
2022                         {
2023                                 indices.Remove (index);
2024                         }
2025
2026                         internal void ReCreate ()
2027                         {
2028                                 indices.Clear ();
2029
2030                                 for (int i = 0; i < owner.Items.Count; i++) {
2031                                         ListBox.ListBoxItem item = owner.Items.GetListBoxItem (i);
2032
2033                                         if (item.Selected)
2034                                                 indices.Add (item.Index);
2035                                 }
2036                         }
2037
2038                         #endregion Private Methods
2039                 }
2040
2041                 /*
2042                         SelectedObjectCollection
2043                 */
2044                 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2045                 {
2046                         private ListBox owner;
2047                         private ArrayList object_items = new ArrayList ();
2048
2049                         public SelectedObjectCollection (ListBox owner)
2050                         {
2051                                 this.owner = owner;
2052                         }
2053
2054                         #region Public Properties
2055                         public virtual int Count {
2056                                 get { return object_items.Count; }
2057                         }
2058
2059                         public virtual bool IsReadOnly {
2060                                 get { return true; }
2061                         }
2062
2063                         public virtual object this [int index] {
2064                                 get {
2065                                         if (index < 0 || index >= Count)
2066                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2067
2068                                         return object_items[index];
2069                                 }
2070                                 set {throw new NotSupportedException ();}
2071                         }
2072
2073                         bool ICollection.IsSynchronized {
2074                                 get { return true; }
2075                         }
2076
2077                         object ICollection.SyncRoot {
2078                                 get { return this; }
2079                         }
2080
2081                         bool IList.IsFixedSize {
2082                                 get { return true; }
2083                         }
2084
2085                         object IList.this[int index] {
2086                                 get { return object_items[index]; }
2087                                 set { throw new NotSupportedException (); }
2088                         }
2089
2090                         #endregion Public Properties
2091
2092                         #region Public Methods
2093                         public virtual bool Contains (object selectedObject)
2094                         {
2095                                 return object_items.Contains (selectedObject);
2096                         }
2097
2098                         public virtual void CopyTo (Array dest, int index)
2099                         {
2100                                 object_items.CopyTo (dest, index);
2101                         }
2102
2103                         int IList.Add (object value)
2104                         {
2105                                 throw new NotSupportedException ();
2106                         }
2107
2108                         void IList.Clear ()
2109                         {
2110                                 throw new NotSupportedException ();
2111                         }
2112
2113                         bool IList.Contains (object selectedIndex)
2114                         {
2115                                 throw new NotImplementedException ();
2116                         }
2117
2118                         int IList.IndexOf (object selectedIndex)
2119                         {
2120                                 return IndexOf ((int) selectedIndex);
2121                         }
2122         \r
2123                         void IList.Insert (int index, object value)
2124                         {
2125                                 throw new NotSupportedException ();
2126                         }
2127
2128                         void IList.Remove (object value)
2129                         {
2130                                 throw new NotSupportedException ();
2131                         }
2132
2133                         void IList.RemoveAt (int index)
2134                         {
2135                                 throw new NotSupportedException ();
2136                         }
2137         \r
2138                         public int IndexOf (int selectedIndex)
2139                         {
2140                                 return object_items.IndexOf (selectedIndex);
2141                         }
2142
2143                         public virtual IEnumerator GetEnumerator ()
2144                         {
2145                                 return object_items.GetEnumerator ();
2146                         }
2147
2148                         #endregion Public Methods
2149
2150                         #region Private Methods
2151                         internal void AddObject (object obj)
2152                         {
2153                                 object_items.Add (obj);
2154                         }
2155
2156                         internal void ClearObjects ()
2157                         {
2158                                 object_items.Clear ();
2159                         }
2160
2161                         internal void ReCreate ()
2162                         {
2163                                 object_items.Clear ();
2164
2165                                 for (int i = 0; i < owner.Items.Count; i++) {
2166                                         ListBox.ListBoxItem item = owner.Items.GetListBoxItem (i);
2167
2168                                         if (item.Selected)
2169                                                 object_items.Add (owner.Items[item.Index]);
2170                                 }
2171                         }
2172
2173                         internal void RemoveObject (object obj)
2174                         {
2175                                 object_items.Remove (obj);
2176                         }
2177
2178
2179
2180                         #endregion Private Methods
2181
2182                 }
2183
2184         }
2185 }
2186