* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TabControl.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-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
31 using System.Runtime.InteropServices;
32 using System.Windows.Forms.Theming;
33 using System.Windows.Forms.VisualStyles;
34
35 namespace System.Windows.Forms {
36 #if NET_2_0
37         [ComVisibleAttribute (true)]
38         [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)]
39 #endif
40         [DefaultEvent("SelectedIndexChanged")]
41         [DefaultProperty("TabPages")]
42         [Designer("System.Windows.Forms.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43         public class TabControl : Control {
44                 #region Fields
45                 private int selected_index = -1;
46                 private TabAlignment alignment;
47                 private TabAppearance appearance;
48                 private TabDrawMode draw_mode;
49                 private bool multiline;
50                 private ImageList image_list;
51                 private Size item_size = Size.Empty;
52                 private bool item_size_manual;
53                 private Point padding;
54                 private int row_count = 0;
55                 private bool hottrack;
56                 private TabPageCollection tab_pages;
57                 private bool show_tool_tips;
58                 private TabSizeMode size_mode;
59                 private bool show_slider = false;
60                 private PushButtonState right_slider_state = PushButtonState.Normal;
61                 private PushButtonState left_slider_state = PushButtonState.Normal;
62                 private int slider_pos = 0;
63                 TabPage entered_tab_page;
64                 bool mouse_down_on_a_tab_page;
65                 ToolTip tooltip;
66                 ToolTip.TipState tooltip_state = ToolTip.TipState.Down;
67                 Timer tooltip_timer;
68
69 #if NET_2_0
70                 private bool rightToLeftLayout;
71 #endif          
72                 #endregion      // Fields
73
74                 #region UIA Framework Events
75 #if NET_2_0
76                 static object UIAHorizontallyScrollableChangedEvent = new object ();
77
78                 internal event EventHandler UIAHorizontallyScrollableChanged {
79                         add { Events.AddHandler (UIAHorizontallyScrollableChangedEvent, value); }
80                         remove { Events.RemoveHandler (UIAHorizontallyScrollableChangedEvent, value); }
81                 }
82
83                 internal void OnUIAHorizontallyScrollableChanged (EventArgs e)
84                 {
85                         EventHandler eh
86                                 = (EventHandler) Events [UIAHorizontallyScrollableChangedEvent];
87                         if (eh != null)
88                                 eh (this, e);
89                 }
90
91                 static object UIAHorizontallyScrolledEvent = new object ();
92
93                 internal event EventHandler UIAHorizontallyScrolled {
94                         add { Events.AddHandler (UIAHorizontallyScrolledEvent, value); }
95                         remove { Events.RemoveHandler (UIAHorizontallyScrolledEvent, value); }
96                 }
97
98                 internal void OnUIAHorizontallyScrolled (EventArgs e)
99                 {
100                         EventHandler eh
101                                 = (EventHandler) Events [UIAHorizontallyScrolledEvent];
102                         if (eh != null)
103                                 eh (this, e);
104                 }
105 #endif
106                 #endregion
107
108                 #region UIA Framework Property
109 #if NET_2_0
110                 internal double UIAHorizontalViewSize {
111                         get { return LeftScrollButtonArea.Left * 100 / TabPages [TabCount - 1].TabBounds.Right; }
112                 }
113 #endif
114                 #endregion
115
116                 #region Public Constructors
117                 public TabControl ()
118                 {
119                         tab_pages = new TabPageCollection (this);
120                         SetStyle (ControlStyles.UserPaint, false);
121                         padding = ThemeEngine.Current.TabControlDefaultPadding;
122
123                         MouseDown += new MouseEventHandler (MouseDownHandler);
124                         MouseLeave += new EventHandler (OnMouseLeave);
125                         MouseMove += new MouseEventHandler (OnMouseMove);
126                         MouseUp += new MouseEventHandler (MouseUpHandler);
127                         SizeChanged += new EventHandler (SizeChangedHandler);
128                 }
129
130                 #endregion      // Public Constructors
131
132                 #region Public Instance Properties
133                 [DefaultValue(TabAlignment.Top)]
134                 [Localizable(true)]
135                 [RefreshProperties(RefreshProperties.All)]
136                 public TabAlignment Alignment {
137                         get { return alignment; }
138                         set {
139                                 if (alignment == value)
140                                         return;
141                                 alignment = value;
142                                 if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
143                                         multiline = true;
144                                 Redraw ();
145                         }
146                 }
147
148                 [DefaultValue(TabAppearance.Normal)]
149                 [Localizable(true)]
150                 public TabAppearance Appearance {
151                         get { return appearance; }
152                         set {
153                                 if (appearance == value)
154                                         return;
155                                 appearance = value;
156                                 Redraw ();
157                         }
158                 }
159
160                 [Browsable(false)]
161                 [EditorBrowsable(EditorBrowsableState.Never)]
162                 public override Color BackColor {
163                         get { return ThemeEngine.Current.ColorControl; }
164                         set { /* nothing happens on set on MS */ }
165                 }
166
167                 [Browsable(false)]
168                 [EditorBrowsable(EditorBrowsableState.Never)]
169                 public override Image BackgroundImage {
170                         get { return base.BackgroundImage; }
171                         set { base.BackgroundImage = value; }
172                 }
173
174 #if NET_2_0
175                 [Browsable (false)]
176                 [EditorBrowsable (EditorBrowsableState.Never)]
177                 public override ImageLayout BackgroundImageLayout {
178                         get { return base.BackgroundImageLayout; }
179                         set { base.BackgroundImageLayout = value; }
180                 }
181 #endif
182                 
183                 public override Rectangle DisplayRectangle {
184                         get {
185                                 return ThemeEngine.Current.TabControlGetDisplayRectangle (this);
186                         }
187                 }
188
189 #if NET_2_0
190                 [EditorBrowsable (EditorBrowsableState.Never)]
191                 protected override bool DoubleBuffered {
192                         get { return base.DoubleBuffered; }
193                         set { base.DoubleBuffered = value; }
194                 }
195 #endif
196
197                 [DefaultValue(TabDrawMode.Normal)]
198                 public TabDrawMode DrawMode {
199                         get { return draw_mode; }
200                         set {
201                                 if (draw_mode == value)
202                                         return;
203                                 draw_mode = value;
204                                 Redraw ();
205                         }
206                 }
207
208                 [Browsable(false)]
209                 [EditorBrowsable(EditorBrowsableState.Never)]
210                 public override Color ForeColor {
211                         get { return base.ForeColor; }
212                         set { base.ForeColor = value; }
213                 }
214
215                 [DefaultValue(false)]
216                 public bool HotTrack {
217                         get { return hottrack; }
218                         set {
219                                 if (hottrack == value)
220                                         return;
221                                 hottrack = value;
222                                 Redraw ();
223                         }
224                 }
225
226 #if NET_2_0
227                 [RefreshProperties (RefreshProperties.Repaint)]
228 #endif
229                 [DefaultValue(null)]
230                 public ImageList ImageList {
231                         get { return image_list; }
232                         set { 
233                                 image_list = value; 
234                                 Redraw ();
235                         }
236                 }
237
238                 [Localizable(true)]
239                 public Size ItemSize {
240                         get {
241                                 if (item_size_manual)
242                                         return item_size;
243
244                                 if (!IsHandleCreated)
245                                         return Size.Empty;
246
247                                 Size size = item_size;
248                                 if (SizeMode != TabSizeMode.Fixed) {
249                                         size.Width += padding.X * 2;
250                                         size.Height += padding.Y * 2;
251                                 }
252
253                                 if (tab_pages.Count == 0)
254                                         size.Width = 0;
255
256                                 return size;
257                         }
258                         set {
259                                 if (value.Height < 0 || value.Width < 0)
260                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
261                                 item_size = value;
262                                 item_size_manual = true;
263                                 Redraw ();
264                         }
265                 }
266
267                 [DefaultValue(false)]
268                 public bool Multiline {
269                         get { return multiline; }
270                         set {
271                                 if (multiline == value)
272                                         return;
273                                 multiline = value;
274                                 if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
275                                         alignment = TabAlignment.Top;
276                                 Redraw ();
277                         }
278                 }
279
280                 [Localizable(true)]
281                 public
282 #if NET_2_0
283                 new
284 #endif
285                 Point Padding {
286                         get { return padding; }
287                         set {
288                                 if (value.X < 0 || value.Y < 0)
289                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
290                                 if (padding == value)
291                                         return;
292                                 padding = value;
293                                 Redraw ();
294                         }
295
296                 }
297
298 #if NET_2_0
299                 [MonoTODO ("RTL not supported")]
300                 [Localizable (true)]
301                 [DefaultValue (false)]
302                 public virtual bool RightToLeftLayout {
303                         get { return this.rightToLeftLayout; }
304                         set {
305                                 if (value != this.rightToLeftLayout) {
306                                         this.rightToLeftLayout = value;
307                                         this.OnRightToLeftLayoutChanged (EventArgs.Empty);
308                                 }
309                         }
310                 }
311 #endif
312
313                 [Browsable(false)]
314                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
315                 public int RowCount {
316                         get { return row_count; }
317                 }
318
319                 [DefaultValue(-1)]
320                 [Browsable(false)]
321                 public int SelectedIndex {
322                         get { return selected_index; }
323                         set {
324
325                                 if (value < -1) {
326 #if NET_2_0
327                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " +
328                                                 "'SelectedIndex' must be greater than or equal to -1.");
329 #else
330                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
331                                                 "'value' must be greater than or equal to -1.");
332 #endif
333                                 }
334                                 if (!this.IsHandleCreated) {
335                                         if (selected_index != value) {
336                                                 selected_index = value;
337 #if !NET_2_0
338                                                 OnSelectedIndexChanged (EventArgs.Empty);
339 #endif
340                                         }
341                                         return;
342                                 }
343
344                                 if (value >= TabCount) {
345                                         if (value != selected_index)
346                                                 OnSelectedIndexChanged (EventArgs.Empty);
347                                         return;
348                                 }
349
350                                 if (value == selected_index) {
351                                         if (selected_index > -1)
352                                                 Invalidate(GetTabRect (selected_index));
353                                         return;
354                                 }
355
356 #if NET_2_0
357                                 TabControlCancelEventArgs ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Deselecting);
358                                 OnDeselecting (ret);
359                                 if (ret.Cancel)
360                                         return;
361
362 #endif
363                                 Focus ();
364                                 int old_index = selected_index;
365                                 int new_index = value;
366
367                                 selected_index = new_index;
368
369 #if NET_2_0
370                                 ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Selecting);
371                                 OnSelecting (ret);
372                                 if (ret.Cancel) {
373                                         selected_index = old_index;
374                                         return;
375                                 }
376 #endif
377
378                                 SuspendLayout ();
379
380                                 Rectangle invalid = Rectangle.Empty;
381                                 bool refresh = false;
382
383                                 if (new_index != -1 && show_slider && new_index < slider_pos) {
384                                         slider_pos = new_index;
385                                         refresh = true;
386                                 }
387
388                                 if (new_index != -1) {
389                                         int le = TabPages[new_index].TabBounds.Right;
390                                         int re = LeftScrollButtonArea.Left;
391                                         if (show_slider && le > re) {
392                                                 int i = 0;
393                                                 for (i = 0; i < new_index - 1; i++) {
394                                                         if (TabPages [i].TabBounds.Left < 0) // tab scrolled off the visible area, ignore
395                                                                 continue;
396
397                                                         if (TabPages [new_index].TabBounds.Right - TabPages[i].TabBounds.Right < re) {
398                                                                 i++;
399                                                                 break;
400                                                         }
401                                                 }
402                                                 slider_pos = i;
403                                                 refresh = true;
404                                         }
405                                 }
406
407                                 if (old_index != -1 && new_index != -1) {
408                                         if (!refresh)
409                                                 invalid = GetTabRect (old_index);
410                                         ((TabPage) Controls[old_index]).SetVisible (false);
411                                 }
412
413                                 TabPage selected = null;
414
415                                 if (new_index != -1) {
416                                         selected = (TabPage) Controls[new_index];
417                                         invalid = Rectangle.Union (invalid, GetTabRect (new_index));
418                                         selected.SetVisible (true);
419                                 }
420
421                                 OnSelectedIndexChanged (EventArgs.Empty);
422
423                                 ResumeLayout ();
424
425                                 if (refresh) {
426                                         SizeTabs ();
427                                         Refresh ();
428                                 } else if (new_index != -1 && selected.Row != BottomRow) {
429                                         DropRow (TabPages[new_index].Row);
430                                         // calculating what to invalidate here seems to be slower then just
431                                         // refreshing the whole thing
432                                         SizeTabs ();
433                                         Refresh ();
434                                 } else {
435                                         SizeTabs ();
436                                         // The lines are drawn on the edges of the tabs so the invalid area should
437                                         // needs to include the extra pixels of line width (but should not
438                                         // overflow the control bounds).
439                                         if (appearance == TabAppearance.Normal) {
440                                                 invalid.Inflate (6, 4);
441                                                 invalid.Intersect (ClientRectangle);
442                                         }
443                                         Invalidate (invalid);
444                                 }
445                         }
446                 }
447
448                 [Browsable(false)]
449                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
450                 public TabPage SelectedTab {
451                         get {
452                                 if (selected_index == -1)
453                                         return null;
454                                 return tab_pages [selected_index];
455                         }
456                         set {
457                                 int index = IndexForTabPage (value);
458                                 if (index == selected_index)
459                                         return;
460                                 SelectedIndex = index;
461                         }
462                 }
463
464                 [DefaultValue(false)]
465                 [Localizable(true)]
466                 public bool ShowToolTips {
467                         get { return show_tool_tips; }
468                         set {
469                                 if (show_tool_tips == value)
470                                         return;
471                                 show_tool_tips = value;
472                         }
473                 }
474
475                 [DefaultValue(TabSizeMode.Normal)]
476                 [RefreshProperties(RefreshProperties.Repaint)]
477                 public TabSizeMode SizeMode {
478                         get { return size_mode; }
479                         set {
480                                 if (size_mode == value)
481                                         return;
482                                 size_mode = value;
483                                 Redraw ();
484                         }
485                 }
486
487                 [Browsable(false)]
488                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
489                 public int TabCount {
490                         get {
491                                 return tab_pages.Count;
492                         }
493                 }
494
495 #if NET_2_0
496                 [Editor ("System.Windows.Forms.Design.TabPageCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
497 #else
498                 [DefaultValue(null)]
499 #endif
500                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
501                 [MergableProperty(false)]
502                 public TabPageCollection TabPages {
503                         get { return tab_pages; }
504                 }
505
506                 [Browsable(false)]
507                 [Bindable(false)]
508                 [EditorBrowsable(EditorBrowsableState.Never)]
509                 public override string Text {
510                         get { return base.Text; }
511                         set { base.Text = value; }
512                 }
513                 #endregion      // Public Instance Properties
514
515                 #region Internal Properties
516                 internal bool ShowSlider {
517                         get { return show_slider; }
518                         set {
519                                 show_slider = value;
520
521 #if NET_2_0
522                                 // UIA Framework Event: HorizontallyScrollable Changed
523                                 OnUIAHorizontallyScrollableChanged (EventArgs.Empty);
524 #endif
525                         }
526                 }
527
528                 internal int SliderPos {
529                         get { return slider_pos; }
530                 }
531
532                 internal PushButtonState RightSliderState {
533                         get { return right_slider_state; }
534                         private set {
535                                 if (right_slider_state == value)
536                                         return;
537                                 PushButtonState old_value = right_slider_state;
538                                 right_slider_state = value;
539                                 if (NeedsToInvalidateScrollButton (old_value, value))
540                                         Invalidate (RightScrollButtonArea);
541                         }
542                 }
543
544                 internal PushButtonState LeftSliderState {
545                         get { return left_slider_state; }
546                         set {
547                                 if (left_slider_state == value)
548                                         return;
549                                 PushButtonState old_value = left_slider_state;
550                                 left_slider_state = value;
551                                 if (NeedsToInvalidateScrollButton (old_value, value))
552                                         Invalidate (LeftScrollButtonArea);
553                         }
554                 }
555
556                 bool NeedsToInvalidateScrollButton (PushButtonState oldState, PushButtonState newState)
557                 {
558                         if ((oldState == PushButtonState.Hot && newState == PushButtonState.Normal) ||
559                                 (oldState == PushButtonState.Normal && newState == PushButtonState.Hot))
560                                 return HasHotElementStyles;
561                         return true;
562                 }
563
564                 internal TabPage EnteredTabPage {
565                         get { return entered_tab_page; }
566                         private set {
567                                 if (entered_tab_page == value)
568                                         return;
569                                 if (HasHotElementStyles) {
570                                         Region area_to_invalidate = new Region ();
571                                         area_to_invalidate.MakeEmpty ();
572                                         if (entered_tab_page != null)
573                                                 area_to_invalidate.Union (entered_tab_page.TabBounds);
574                                         entered_tab_page = value;
575                                         if (entered_tab_page != null)
576                                                 area_to_invalidate.Union (entered_tab_page.TabBounds);
577                                         Invalidate (area_to_invalidate);
578                                         area_to_invalidate.Dispose ();
579                                 } else
580                                         entered_tab_page = value;
581
582                                 if (value == null)
583                                         CloseToolTip ();
584                                 else
585                                         SetToolTip (GetToolTipText (value));
586                         }
587                 }
588                 #endregion      // Internal Properties
589
590                 #region Protected Instance Properties
591                 protected override CreateParams CreateParams {
592                         get {
593                                 CreateParams c = base.CreateParams;
594                                 return c;
595                         }
596                 }
597
598                 protected override Size DefaultSize {
599                         get { return new Size (200, 100); }  
600                 }
601
602                 #endregion      // Protected Instance Properties
603
604                 #region Public Instance Methods
605                 public Rectangle GetTabRect (int index)
606                 {
607                         TabPage page = GetTab (index);
608                         return page.TabBounds;
609                 }
610
611                 public Control GetControl (int index)
612                 {
613                         return GetTab (index);
614                 }
615
616 #if NET_2_0
617                 public void SelectTab (TabPage tabPage)
618                 {
619                         if (tabPage == null)
620                                 throw new ArgumentNullException ("tabPage");
621
622                         SelectTab (this.tab_pages [tabPage]);
623                 }
624
625                 public void SelectTab (string tabPageName)
626                 {
627                         if (tabPageName == null)
628                                 throw new ArgumentNullException ("tabPageName");
629
630                         SelectTab (this.tab_pages [tabPageName]);
631                 }
632
633                 public void SelectTab (int index)
634                 {
635                         if (index < 0 || index > this.tab_pages.Count - 1)
636                                 throw new ArgumentOutOfRangeException ("index");
637                                 
638                         SelectedIndex = index;
639                 }
640
641                 public void DeselectTab (TabPage tabPage)
642                 {
643                         if (tabPage == null)
644                                 throw new ArgumentNullException ("tabPage");
645
646                         DeselectTab (this.tab_pages [tabPage]);
647                 }
648
649                 public void DeselectTab (string tabPageName)
650                 {
651                         if (tabPageName == null)
652                                 throw new ArgumentNullException ("tabPageName");
653
654                         DeselectTab (this.tab_pages [tabPageName]);
655                 }
656
657                 public void DeselectTab (int index)
658                 {
659                         if (index == SelectedIndex) {
660                                 if (index >= 0 && index < this.tab_pages.Count - 1)
661                                         SelectedIndex = ++index;
662                                 else
663                                         SelectedIndex = 0;
664                         }
665                 }
666
667 #endif
668
669                 public override string ToString ()
670                 {
671                         string res = String.Concat (base.ToString (),
672                                         ", TabPages.Count: ",
673                                         TabCount);
674                         if (TabCount > 0)
675                                 res = String.Concat (res, ", TabPages[0]: ",
676                                                 TabPages [0]);
677                         return res;
678                 }
679
680                 #endregion      // Public Instance Methods
681
682                 #region Protected Instance Methods
683
684                 #region Handles
685                 protected override Control.ControlCollection CreateControlsInstance ()
686                 {
687                         return new TabControl.ControlCollection (this);
688                 }
689
690                 protected override void CreateHandle ()
691                 {
692                         base.CreateHandle ();
693                         selected_index = (selected_index >= TabCount ? (TabCount > 0 ? 0 : -1) : selected_index);
694
695                         if (TabCount > 0) {
696                                 if (selected_index > -1)
697                                         this.SelectedTab.SetVisible(true);
698                                 else
699                                         tab_pages[0].SetVisible(true);
700                         }
701                         ResizeTabPages ();
702                 }
703
704                 protected override void OnHandleCreated (EventArgs e)
705                 {
706                         base.OnHandleCreated (e);
707                 }
708
709                 protected override void OnHandleDestroyed (EventArgs e)
710                 {
711                         base.OnHandleDestroyed (e);
712                 }
713
714                 protected override void Dispose (bool disposing)
715                 {
716                         CloseToolTip ();
717                         base.Dispose (disposing);
718                 }
719
720                 #endregion
721
722                 #region Events
723                 protected virtual void OnDrawItem (DrawItemEventArgs e)
724                 {
725                         if (DrawMode != TabDrawMode.OwnerDrawFixed)
726                                 return;
727
728                         DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
729                         if (eh != null)
730                                 eh (this, e);
731                 }
732
733                 internal void OnDrawItemInternal (DrawItemEventArgs e)
734                 {
735                         OnDrawItem (e);
736                 }
737
738                 protected override void OnFontChanged (EventArgs e)
739                 {
740                         base.OnFontChanged (e);
741                         ResizeTabPages ();
742                 }
743
744                 protected override void OnResize (EventArgs e)
745                 {
746                         base.OnResize (e);
747                 }
748
749                 protected override void OnStyleChanged (EventArgs e)
750                 {
751                         base.OnStyleChanged (e);
752                 }
753
754                 protected virtual void OnSelectedIndexChanged (EventArgs e)
755                 {
756                         EventHandler eh = (EventHandler) (Events[SelectedIndexChangedEvent]);
757                         if (eh != null)
758                                 eh (this, e);
759                 }
760
761                 internal override void OnPaintInternal (PaintEventArgs pe)
762                 {
763                         if (GetStyle (ControlStyles.UserPaint))
764                                 return;
765
766                         Draw (pe.Graphics, pe.ClipRectangle);
767                         pe.Handled = true;
768                 }
769
770 #if NET_2_0
771                 protected override void OnEnter (EventArgs e)
772                 {
773                         base.OnEnter (e);
774                         if (SelectedTab != null)
775                                 SelectedTab.FireEnter ();
776                 }
777
778                 protected override void OnLeave (EventArgs e)
779                 {
780                         if (SelectedTab != null)
781                                 SelectedTab.FireLeave ();
782                         base.OnLeave (e);
783                 }
784
785                 [EditorBrowsable (EditorBrowsableState.Advanced)]
786                 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
787                 {
788                         EventHandler eh = (EventHandler) (Events[RightToLeftLayoutChangedEvent]);
789                         if (eh != null)
790                                 eh (this, e);
791                 }
792
793                 [EditorBrowsable (EditorBrowsableState.Never)]
794                 protected override void ScaleCore (float dx, float dy)
795                 {
796                         base.ScaleCore (dx, dy);
797                 }
798
799                 protected virtual void OnDeselecting (TabControlCancelEventArgs e)
800                 {
801                         TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[DeselectingEvent]);
802                         if (eh != null)
803                                 eh (this, e);
804
805                         if (!e.Cancel)
806                                 OnDeselected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Deselected));
807                 }
808
809                 protected virtual void OnDeselected (TabControlEventArgs e)
810                 {
811                         TabControlEventHandler eh = (TabControlEventHandler) (Events[DeselectedEvent]);
812                         if (eh != null)
813                                 eh (this, e);
814
815                         if (this.SelectedTab != null)
816                                 this.SelectedTab.FireLeave ();
817                 }
818
819                 protected virtual void OnSelecting (TabControlCancelEventArgs e)
820                 {
821                         TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[SelectingEvent]);
822                         if (eh != null)
823                                 eh (this, e);
824
825                         if (!e.Cancel)
826                                 OnSelected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Selected));
827                 }
828
829                 protected virtual void OnSelected (TabControlEventArgs e)
830                 {
831                         TabControlEventHandler eh = (TabControlEventHandler) (Events[SelectedEvent]);
832                         if (eh != null)
833                                 eh (this, e);
834
835                         if (this.SelectedTab != null)
836                                 this.SelectedTab.FireEnter ();
837                 }
838 #endif
839
840                 #endregion
841
842                 #region Keys
843                 protected override bool ProcessKeyPreview (ref Message m)
844                 {
845                         return base.ProcessKeyPreview (ref m);
846                 }
847
848                 protected override void OnKeyDown (KeyEventArgs ke)
849                 {
850                         base.OnKeyDown (ke);
851                         if (ke.Handled)
852                                 return;
853
854                         if (ke.KeyCode == Keys.Tab && (ke.KeyData & Keys.Control) != 0) {
855                                 if ((ke.KeyData & Keys.Shift) == 0)
856                                         SelectedIndex = (SelectedIndex + 1) % TabCount;
857                                 else
858                                         SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount;
859                                 ke.Handled = true;
860                         } else if (ke.KeyCode == Keys.Home) {
861                                 SelectedIndex = 0;
862                                 ke.Handled = true;
863                         } else if (ke.KeyCode == Keys.End) {
864                                 SelectedIndex = TabCount - 1;
865                                 ke.Handled = true;
866                         } else if (NavigateTabs (ke.KeyCode))
867                                 ke.Handled = true;
868                 }
869
870                 protected override bool IsInputKey (Keys keyData)
871                 {
872                         switch (keyData & Keys.KeyCode) {
873                         case Keys.Home:
874                         case Keys.End:
875                         case Keys.Left:
876                         case Keys.Right:
877                         case Keys.Up:
878                         case Keys.Down:
879                                 return true;
880                         }
881                         return base.IsInputKey (keyData);
882                 }
883                 
884                 private bool NavigateTabs (Keys keycode)
885                 {
886                         bool move_left = false;
887                         bool move_right = false;
888                         
889                         if (alignment == TabAlignment.Bottom || alignment == TabAlignment.Top) {
890                                 if (keycode == Keys.Left)
891                                         move_left = true;
892                                 else if (keycode == Keys.Right)
893                                         move_right = true;
894                         } else {
895                                 if (keycode == Keys.Up)
896                                         move_left = true;
897                                 else if (keycode == Keys.Down)
898                                         move_right = true;
899                         }
900                                 
901                         if (move_left) {
902                                 if (SelectedIndex > 0) {
903                                         SelectedIndex--;
904                                         return true;
905                                 }
906                         }
907                         
908                         if (move_right) {
909                                 if (SelectedIndex < TabCount - 1) {
910                                         SelectedIndex++;
911                                         return true;
912                                 }
913                         }
914                         
915                         return false;
916                 }
917                 #endregion
918
919                 #region Pages Collection
920                 protected void RemoveAll ()
921                 {
922                         Controls.Clear ();
923                 }
924
925                 protected virtual object [] GetItems ()
926                 {
927                         TabPage [] pages = new TabPage [Controls.Count];
928                         Controls.CopyTo (pages, 0);
929                         return pages;
930                 }
931
932                 protected virtual object [] GetItems (Type baseType)
933                 {
934                         object[] pages = (object[])Array.CreateInstance (baseType, Controls.Count);
935                         Controls.CopyTo (pages, 0);
936                         return pages;
937                 }
938                 #endregion
939
940 #if NET_2_0
941                 protected void UpdateTabSelection (bool updateFocus)
942 #else
943                 protected void UpdateTabSelection (bool uiselected)
944 #endif
945                 {
946                         ResizeTabPages ();
947                 }
948
949                 protected string GetToolTipText (object item)
950                 {
951                         TabPage page = (TabPage) item;
952                         return page.ToolTipText;
953                 }
954
955                 protected override void WndProc (ref Message m)
956                 {
957                         switch ((Msg)m.Msg) {
958                         case Msg.WM_SETFOCUS:
959                                 if (selected_index == -1 && this.TabCount > 0)
960                                         this.SelectedIndex = 0;
961                                 if (selected_index != -1)
962                                         Invalidate(GetTabRect(selected_index));
963                                 base.WndProc (ref m);
964                                 break;
965                         case Msg.WM_KILLFOCUS:
966                                 if (selected_index != -1)
967                                         Invalidate(GetTabRect(selected_index));
968                                 base.WndProc (ref m);
969                                 break;
970                         default:
971                                 base.WndProc (ref m);
972                                 break;
973                         }
974                 }
975
976                 #endregion      // Protected Instance Methods
977
978                 #region Internal & Private Methods
979                 private bool CanScrollRight {
980                         get {
981                                 return (slider_pos < TabCount - 1);
982                         }
983                 }
984
985                 private bool CanScrollLeft {
986                         get { return slider_pos > 0; }
987                 }
988
989                 private void MouseDownHandler (object sender, MouseEventArgs e)
990                 {
991                         if ((e.Button & MouseButtons.Left) == 0)
992                                 return;
993
994                         if (ShowSlider) {
995                                 Rectangle right = RightScrollButtonArea;
996                                 Rectangle left = LeftScrollButtonArea;
997                                 if (right.Contains (e.X, e.Y)) {
998                                         right_slider_state = PushButtonState.Pressed;
999                                         if (CanScrollRight) {
1000                                                 slider_pos++;
1001                                                 SizeTabs ();
1002
1003 #if NET_2_0
1004                                                 // UIA Framework Event: Horizontally Scrolled
1005                                                 OnUIAHorizontallyScrolled (EventArgs.Empty);
1006 #endif
1007
1008                                                 switch (this.Alignment) {
1009                                                         case TabAlignment.Top:
1010                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
1011                                                                 break;
1012                                                         case TabAlignment.Bottom:
1013                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
1014                                                                 break;
1015                                                         case TabAlignment.Left:
1016                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
1017                                                                 break;
1018                                                         case TabAlignment.Right:
1019                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
1020                                                                 break;
1021                                                 }
1022                                                 
1023                                         } else {
1024                                                 Invalidate (right);
1025                                         }
1026                                         return;
1027                                 } else if (left.Contains (e.X, e.Y)) {
1028                                         left_slider_state = PushButtonState.Pressed;
1029                                         if (CanScrollLeft) {
1030                                                 slider_pos--;
1031                                                 SizeTabs ();
1032
1033 #if NET_2_0
1034                                                 // UIA Framework Event: Horizontally Scrolled
1035                                                 OnUIAHorizontallyScrolled (EventArgs.Empty);
1036 #endif
1037
1038                                                 switch (this.Alignment) {
1039                                                         case TabAlignment.Top:
1040                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
1041                                                                 break;
1042                                                         case TabAlignment.Bottom:
1043                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
1044                                                                 break;
1045                                                         case TabAlignment.Left:
1046                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
1047                                                                 break;
1048                                                         case TabAlignment.Right:
1049                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
1050                                                                 break;
1051                                                 }
1052                                         } else {
1053                                                 Invalidate (left);
1054                                         }
1055                                         return;
1056                                 }
1057                         }
1058
1059                         int count = Controls.Count;
1060                         for (int i = SliderPos; i < count; i++) {
1061                                 if (!GetTabRect (i).Contains (e.X, e.Y))
1062                                         continue;
1063                                 SelectedIndex = i;
1064                                 mouse_down_on_a_tab_page = true;
1065                                 break;
1066                         }
1067                 }
1068
1069                 private void MouseUpHandler (object sender, MouseEventArgs e)
1070                 {
1071                         mouse_down_on_a_tab_page = false;
1072                         if (ShowSlider && (left_slider_state == PushButtonState.Pressed || right_slider_state == PushButtonState.Pressed)) {
1073                                 Rectangle invalid;
1074                                 if (left_slider_state == PushButtonState.Pressed) {
1075                                         invalid = LeftScrollButtonArea;
1076                                         left_slider_state = GetScrollButtonState (invalid, e.Location);
1077                                 } else {
1078                                         invalid = RightScrollButtonArea;
1079                                         right_slider_state = GetScrollButtonState (invalid, e.Location);
1080                                 }
1081                                 Invalidate (invalid);
1082                         }
1083                 }
1084
1085                 bool HasHotElementStyles {
1086                         get {
1087                                 return ThemeElements.CurrentTheme.TabControlPainter.HasHotElementStyles (this);
1088                         }
1089                 }
1090
1091                 Rectangle LeftScrollButtonArea {
1092                         get {
1093                                 return ThemeElements.CurrentTheme.TabControlPainter.GetLeftScrollRect (this);
1094                         }
1095                 }
1096
1097                 Rectangle RightScrollButtonArea {
1098                         get {
1099                                 return ThemeElements.CurrentTheme.TabControlPainter.GetRightScrollRect (this);
1100                         }
1101                 }
1102
1103                 static PushButtonState GetScrollButtonState (Rectangle scrollButtonArea, Point cursorLocation)
1104                 {
1105                         return scrollButtonArea.Contains (cursorLocation) ? PushButtonState.Hot : PushButtonState.Normal;
1106                 }
1107
1108                 private void SizeChangedHandler (object sender, EventArgs e)
1109                 {
1110                         Redraw ();
1111                 }
1112
1113                 internal int IndexForTabPage (TabPage page)
1114                 {
1115                         for (int i = 0; i < tab_pages.Count; i++) {
1116                                 if (page == tab_pages [i])
1117                                         return i;
1118                         }
1119                         return -1;
1120                 }
1121
1122                 private void ResizeTabPages ()
1123                 {
1124                         CalcTabRows ();
1125                         SizeTabs ();
1126                         Rectangle r = DisplayRectangle;
1127                         foreach (TabPage page in Controls) {
1128                                 page.Bounds = r;
1129                         }
1130                 }
1131
1132                 private int MinimumTabWidth {
1133                         get {
1134                                 return ThemeEngine.Current.TabControlMinimumTabWidth;
1135                         }
1136                 }
1137
1138                 private Size TabSpacing {
1139                         get {
1140                                 return ThemeEngine.Current.TabControlGetSpacing (this);
1141                         }
1142                 }
1143
1144                 private void CalcTabRows ()
1145                 {
1146                         switch (Alignment) {
1147                         case TabAlignment.Right:
1148                         case TabAlignment.Left:
1149                                 CalcTabRows (Height);
1150                                 break;
1151                         default:
1152                                 CalcTabRows (Width);
1153                                 break;
1154                         }
1155                 }
1156
1157                 private void CalcTabRows (int row_width)
1158                 {
1159                         int xpos = 0;
1160                         int ypos = 0;
1161                         Size spacing = TabSpacing;
1162
1163                         if (TabPages.Count > 0)
1164                                 row_count = 1;
1165                         show_slider = false;
1166                         
1167                         CalculateItemSize ();
1168
1169                         for (int i = 0; i < TabPages.Count; i++) {
1170                                 TabPage page = TabPages [i];
1171                                 int aux = 0;
1172                                 SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, 0, ref aux, true);
1173                         }
1174
1175                         if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow)
1176                                 DropRow (TabPages [SelectedIndex].Row);
1177                 }
1178
1179                 // ItemSize per-se is used mostly only to retrieve the Height,
1180                 // since the actual Width of the tabs is computed individually,
1181                 // except when SizeMode is TabSizeMode.Fixed, where Width is used as well.
1182                 private void CalculateItemSize ()
1183                 {
1184                         if (item_size_manual)
1185                                 return;
1186
1187                         SizeF size;
1188                         if (tab_pages.Count > 0) {
1189                                 // .Net uses the first tab page if available.
1190                                 size = TextRenderer.MeasureString (tab_pages [0].Text, Font);
1191
1192                         } else {
1193                                 size = TextRenderer.MeasureString ("a", Font);
1194                                 size.Width = 0;
1195                         }
1196
1197                         if (size_mode == TabSizeMode.Fixed)
1198                                 size.Width = 96;
1199                         if (size.Width < MinimumTabWidth)
1200                                 size.Width = MinimumTabWidth;
1201                         if (image_list != null && image_list.ImageSize.Height > size.Height)
1202                                 size.Height = image_list.ImageSize.Height;
1203
1204                         item_size = size.ToSize ();
1205                 }
1206
1207                 private int BottomRow {
1208                         get { return 1; }
1209                 }
1210
1211                 private int Direction
1212                 {
1213                         get {
1214                                 return 1;
1215                         }
1216                 }
1217
1218                 private void DropRow (int row)
1219                 {
1220                         if (Appearance != TabAppearance.Normal)
1221                                 return;
1222
1223                         int bottom = BottomRow;
1224                         int direction = Direction;
1225
1226                         foreach (TabPage page in TabPages) {
1227                                 if (page.Row == row) {
1228                                         page.Row = bottom;
1229                                 } else if (direction == 1 && page.Row < row) {
1230                                         page.Row += direction;
1231                                 } else if (direction == -1 && page.Row > row) {
1232                                         page.Row += direction;
1233                                 }
1234                         }
1235                 }
1236
1237                 private int CalcYPos ()
1238                 {
1239                         if (Alignment == TabAlignment.Bottom || Alignment == TabAlignment.Left)
1240                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom;
1241
1242                         if (Appearance == TabAppearance.Normal)
1243                                 return this.ClientRectangle.Y + ThemeEngine.Current.TabControlSelectedDelta.Y;
1244
1245                         return this.ClientRectangle.Y;
1246
1247                 }
1248
1249                 private int CalcXPos ()
1250                 {
1251                         if (Alignment == TabAlignment.Right)
1252                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Right;
1253
1254                         if (Appearance == TabAppearance.Normal)
1255                                 return this.ClientRectangle.X + ThemeEngine.Current.TabControlSelectedDelta.X;
1256
1257                         return this.ClientRectangle.X;
1258                 }
1259
1260                 private void SizeTabs ()
1261                 {
1262                         switch (Alignment) {
1263                         case TabAlignment.Right:
1264                         case TabAlignment.Left:
1265                                 SizeTabs (Height, true);
1266                                 break;
1267                         default:
1268                                 SizeTabs (Width, false);
1269                                 break;
1270                         }
1271                 }
1272                 
1273                 private void SizeTabs (int row_width, bool vertical)
1274                 {
1275                         int ypos = 0;
1276                         int xpos = 0;
1277                         int prev_row = 1;
1278                         Size spacing = TabSpacing;
1279                         int begin_prev = 0;
1280
1281                         if (TabPages.Count == 0)
1282                                 return;
1283
1284                         prev_row = TabPages [0].Row;
1285
1286                         // Reset the slider position if the slider isn't needed
1287                         // anymore (ie window size was increased so all tabs are visible)
1288                         if (!show_slider)
1289                                 slider_pos = 0;
1290                         else {
1291                                 // set X = -1 for marking tabs that are not visible due to scrolling
1292                                 for (int i = 0; i < slider_pos; i++) {
1293                                         TabPage page = TabPages[i];
1294                                         Rectangle x = page.TabBounds;
1295                                         x.X = -1;
1296                                         page.TabBounds = x;
1297                                 }
1298                         }
1299                         
1300                         for (int i = slider_pos; i < TabPages.Count; i++) {
1301                                 TabPage page = TabPages[i];
1302                                 SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false);
1303                                 prev_row = page.Row;
1304                         }
1305
1306                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1307                                 FillRow (begin_prev, TabPages.Count - 1,
1308                                                 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), 
1309                                                 spacing, vertical);
1310                         }
1311
1312                         if (SelectedIndex != -1) {
1313                                 ExpandSelected (TabPages [SelectedIndex], 0, row_width - 1);
1314                         }
1315                 }
1316                 
1317                 private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos, 
1318                                                                 Size spacing, int prev_row, ref int begin_prev, bool widthOnly) 
1319                 {                               
1320                         int width, height = 0;
1321
1322                         if (SizeMode == TabSizeMode.Fixed) {
1323                                 width = item_size.Width;
1324                         } else {                        
1325                                 width = MeasureStringWidth (DeviceContext, page.Text, page.Font);
1326                                 width += (Padding.X * 2) + 2;
1327
1328                                 if (ImageList != null && page.ImageIndex >= 0) {
1329                                         width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X;
1330
1331                                         int image_size = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y;
1332                                         if (item_size.Height < image_size)
1333                                                 item_size.Height = image_size;
1334                                 }
1335
1336                                 if (width < MinimumTabWidth)
1337                                         width = MinimumTabWidth;
1338                         }
1339
1340                         // Use ItemSize property to recover the padding info as well.
1341                         height = ItemSize.Height - ThemeEngine.Current.TabControlSelectedDelta.Height; // full height only for selected tab
1342
1343                         if (i == SelectedIndex)
1344                                 width += ThemeEngine.Current.TabControlSelectedSpacing;
1345                         
1346                         if (widthOnly) {
1347                                 page.TabBounds = new Rectangle (xpos, 0, width, 0);
1348                                 page.Row = row_count;
1349                                 if (xpos + width > row_width && multiline) {
1350                                         xpos = 0;
1351                                         row_count++;
1352                                 } else if (xpos + width > row_width) {
1353                                         show_slider = true;     
1354                                 }
1355                                 if (i == selected_index && show_slider) {
1356                                         for (int j = i-1; j >= 0; j--) {
1357                                                 if (TabPages [j].TabBounds.Left < xpos + width - row_width) {
1358                                                         slider_pos = j+1;
1359                                                         break;
1360                                                 }
1361                                         }
1362                                 }
1363                         } else {
1364                                 if (page.Row != prev_row) {
1365                                         xpos = 0;
1366                                 }
1367
1368                                 switch (Alignment) {
1369                                         case TabAlignment.Top:
1370                                                 page.TabBounds = new Rectangle (
1371                                                         xpos + CalcXPos (),
1372                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1373                                                         width, 
1374                                                         height);
1375                                                 break;
1376                                         case TabAlignment.Bottom:
1377                                                 page.TabBounds = new Rectangle (
1378                                                         xpos + CalcXPos (),
1379                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1380                                                         width, 
1381                                                         height);
1382                                                 break;
1383                                         case TabAlignment.Left:
1384                                                 if (Appearance == TabAppearance.Normal) {
1385                                                         // tab rows are positioned right to left
1386                                                         page.TabBounds = new Rectangle (
1387                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1388                                                                 xpos,
1389                                                                 height, 
1390                                                                 width);
1391                                                 } else {
1392                                                         // tab rows are positioned left to right
1393                                                         page.TabBounds = new Rectangle (
1394                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1395                                                                 xpos,
1396                                                                 height, 
1397                                                                 width);
1398                                                 }
1399
1400                                                 break;
1401                                         case TabAlignment.Right:
1402                                                 if (Appearance == TabAppearance.Normal) {
1403                                                         // tab rows are positioned left to right
1404                                                         page.TabBounds = new Rectangle (
1405                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1406                                                                 xpos,
1407                                                                 height, 
1408                                                                 width);
1409                                                 } else {
1410                                                         // tab rows are positioned right to left
1411                                                         page.TabBounds = new Rectangle (
1412                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1413                                                                 xpos,
1414                                                                 height, 
1415                                                                 width);
1416                                                 }
1417
1418                                                 break;
1419                                 }
1420                         
1421                                 if (page.Row != prev_row) {
1422                                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1423                                                 bool vertical = alignment == TabAlignment.Right || alignment == TabAlignment.Left;
1424                                                 int offset = vertical ? TabPages [i - 1].TabBounds.Bottom : TabPages [i - 1].TabBounds.Right;
1425                                                 FillRow (begin_prev, i - 1, ((row_width - offset) / (i - begin_prev)), spacing,
1426                                                         vertical);
1427                                         }
1428                                         begin_prev = i;
1429                                 }       
1430                         }
1431
1432                         xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing;
1433                 }
1434
1435                 private void FillRow (int start, int end, int amount, Size spacing, bool vertical) 
1436                 {
1437                         if (vertical)
1438                                 FillRowV (start, end, amount, spacing);
1439                         else
1440                                 FillRow (start, end, amount, spacing);
1441                 }
1442
1443                 private void FillRow (int start, int end, int amount, Size spacing)
1444                 {
1445                         int xpos = TabPages [start].TabBounds.Left;
1446                         for (int i = start; i <= end; i++) {
1447                                 TabPage page = TabPages [i];
1448                                 int left = xpos;
1449                                 int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
1450
1451                                 page.TabBounds = new Rectangle (left, page.TabBounds.Top,
1452                                                 width, page.TabBounds.Height);
1453                                 xpos = page.TabBounds.Right + 1 + spacing.Width;
1454                         }
1455                 }
1456
1457                 private void FillRowV (int start, int end, int amount, Size spacing)
1458                 {
1459                         int ypos = TabPages [start].TabBounds.Top;
1460                         for (int i = start; i <= end; i++) {
1461                                 TabPage page = TabPages [i];
1462                                 int top = ypos;
1463                                 int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
1464
1465                                 page.TabBounds = new Rectangle (page.TabBounds.Left, top,
1466                                                 page.TabBounds.Width, height);
1467                                 ypos = page.TabBounds.Bottom + 1;
1468                         }
1469                 }
1470
1471                 private void ExpandSelected (TabPage page, int left_edge, int right_edge)
1472                 {
1473                         if (Appearance != TabAppearance.Normal)
1474                                 return;
1475
1476                         Rectangle r = page.TabBounds;
1477                         switch (Alignment) {
1478                                 case TabAlignment.Top:
1479                                 case TabAlignment.Left:
1480                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1481                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1482                                         break;
1483                                 case TabAlignment.Bottom:
1484                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1485                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1486                                         break;
1487                                 case TabAlignment.Right:
1488                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1489                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1490                                         break;
1491                         }
1492
1493                         r.Width += ThemeEngine.Current.TabControlSelectedDelta.Width;
1494                         r.Height += ThemeEngine.Current.TabControlSelectedDelta.Height;
1495                         if (r.Left < left_edge)
1496                                 r.X = left_edge;
1497                         // Adjustment can't be used for right alignment, since it is
1498                         // the only one that has a different X origin than 0
1499                         if (r.Right > right_edge && SizeMode != TabSizeMode.Normal &&
1500                                         alignment != TabAlignment.Right)
1501                                 r.Width = right_edge - r.X;
1502                         page.TabBounds = r;
1503                 }
1504
1505                 private void Draw (Graphics dc, Rectangle clip)
1506                 {
1507                         ThemeEngine.Current.DrawTabControl (dc, clip, this);
1508                 }
1509
1510                 private TabPage GetTab (int index)
1511                 {
1512                         return Controls [index] as TabPage;
1513                 }
1514
1515                 private void SetTab (int index, TabPage value)
1516                 {
1517                         if (!tab_pages.Contains (value)) {
1518                                 this.Controls.Add (value);
1519                         }
1520                         this.Controls.RemoveAt (index);
1521                         this.Controls.SetChildIndex (value, index);
1522                         Redraw ();
1523                 }
1524 #if NET_2_0
1525                 private void InsertTab (int index, TabPage value)
1526                 {
1527                         if (!tab_pages.Contains (value)) {
1528                                 this.Controls.Add (value);
1529                         }
1530                         this.Controls.SetChildIndex (value, index);
1531                         Redraw ();
1532                 }
1533 #endif
1534                 internal void Redraw ()
1535                 {
1536                         if (!IsHandleCreated)
1537                                 return;
1538
1539                         ResizeTabPages ();
1540                         Refresh ();
1541                 }
1542
1543                 private int MeasureStringWidth (Graphics graphics, string text, Font font) 
1544                 {
1545                         if (text == String.Empty)
1546                                 return 0;
1547                         StringFormat format = new StringFormat();
1548                         RectangleF rect = new RectangleF(0, 0, 1000, 1000);
1549                         CharacterRange[] ranges = { new CharacterRange(0, text.Length) };
1550                         Region[] regions = new Region[1];
1551
1552                         format.SetMeasurableCharacterRanges(ranges);
1553                         format.FormatFlags = StringFormatFlags.NoClip;
1554                         format.FormatFlags |= StringFormatFlags.NoWrap;
1555                         regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format);
1556                         rect = regions[0].GetBounds(graphics);
1557
1558                         return (int)(rect.Width);
1559                 }
1560
1561                 void SetToolTip (string text)
1562                 {
1563                         if (!show_tool_tips)
1564                                 return;
1565
1566                         if (text == null || text.Length == 0) {
1567                                 CloseToolTip ();
1568                                 return;
1569                         }
1570
1571                         if (tooltip == null) {
1572                                 tooltip = new ToolTip ();
1573                                 tooltip_timer = new Timer ();
1574                                 tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
1575                         }
1576
1577                         CloseToolTip ();
1578
1579                         tooltip_state = ToolTip.TipState.Initial;
1580                         tooltip_timer.Interval = 500;
1581                         tooltip_timer.Start ();
1582                 }
1583
1584                 void CloseToolTip ()
1585                 {
1586                         if (tooltip == null)
1587                                 return;
1588
1589                         tooltip.Hide (this);
1590                         tooltip_timer.Stop ();
1591                         tooltip_state = ToolTip.TipState.Down;
1592                 }
1593
1594                 void ToolTipTimerTick (object o, EventArgs args)
1595                 {
1596                         switch (tooltip_state) {
1597                                 case ToolTip.TipState.Initial:
1598                                         tooltip_timer.Stop ();
1599                                         tooltip_timer.Interval = 5000;
1600                                         tooltip_timer.Start ();
1601                                         tooltip_state = ToolTip.TipState.Show;
1602                                         tooltip.Present (this, GetToolTipText (EnteredTabPage));
1603                                         break;
1604                                 case ToolTip.TipState.Show:
1605                                         CloseToolTip ();
1606                                         break;
1607                         }
1608                 }
1609
1610                 void OnMouseMove (object sender, MouseEventArgs e)
1611                 {
1612                         if (!mouse_down_on_a_tab_page && ShowSlider) {
1613                                 if (LeftSliderState == PushButtonState.Pressed ||
1614                                         RightSliderState == PushButtonState.Pressed)
1615                                         return;
1616                                 if (LeftScrollButtonArea.Contains (e.Location)) {
1617                                         LeftSliderState = PushButtonState.Hot;
1618                                         RightSliderState = PushButtonState.Normal;
1619                                         EnteredTabPage = null;
1620                                         return;
1621                                 }
1622                                 if (RightScrollButtonArea.Contains (e.Location)) {
1623                                         RightSliderState = PushButtonState.Hot;
1624                                         LeftSliderState = PushButtonState.Normal;
1625                                         EnteredTabPage = null;
1626                                         return;
1627                                 }
1628                                 LeftSliderState = PushButtonState.Normal;
1629                                 RightSliderState = PushButtonState.Normal;
1630                         }
1631                         if (EnteredTabPage != null && EnteredTabPage.TabBounds.Contains (e.Location))
1632                                 return;
1633                         for (int index = 0; index < TabCount; index++) {
1634                                 TabPage tab_page = TabPages[index];
1635                                 if (tab_page.TabBounds.Contains (e.Location)) {
1636                                         EnteredTabPage = tab_page;
1637                                         return;
1638                                 }
1639                         }
1640                         EnteredTabPage = null;
1641                 }
1642
1643                 void OnMouseLeave (object sender, EventArgs e)
1644                 {
1645                         if (ShowSlider) {
1646                                 LeftSliderState = PushButtonState.Normal;
1647                                 RightSliderState = PushButtonState.Normal;
1648                         }
1649                         EnteredTabPage = null;
1650                 }
1651                 #endregion      // Internal & Private Methods
1652
1653                 #region Events
1654                 [Browsable(false)]
1655                 [EditorBrowsable(EditorBrowsableState.Never)]
1656                 public new event EventHandler BackColorChanged {
1657                         add { base.BackColorChanged += value; }
1658                         remove { base.BackColorChanged -= value; }
1659                 }
1660
1661                 [Browsable(false)]
1662                 [EditorBrowsable(EditorBrowsableState.Never)]
1663                 public new event EventHandler BackgroundImageChanged {
1664                         add { base.BackgroundImageChanged += value; }
1665                         remove { base.BackgroundImageChanged -= value; }
1666                 }
1667
1668 #if NET_2_0
1669                 [Browsable (false)]
1670                 [EditorBrowsable (EditorBrowsableState.Never)]
1671                 public new event EventHandler BackgroundImageLayoutChanged
1672                 {
1673                         add { base.BackgroundImageLayoutChanged += value; }
1674                         remove { base.BackgroundImageLayoutChanged -= value; }
1675                 }
1676 #endif
1677
1678                 [Browsable(false)]
1679                 [EditorBrowsable(EditorBrowsableState.Never)]
1680                 public new event EventHandler ForeColorChanged {
1681                         add { base.ForeColorChanged += value; }
1682                         remove { base.ForeColorChanged -= value; }
1683                 }
1684
1685                 [Browsable(false)]
1686                 [EditorBrowsable(EditorBrowsableState.Never)]
1687                 public new event PaintEventHandler Paint {
1688                         add { base.Paint += value; }
1689                         remove { base.Paint -= value; }
1690                 }
1691
1692                 [Browsable(false)]
1693                 [EditorBrowsable(EditorBrowsableState.Never)]
1694                 public new event EventHandler TextChanged {
1695                         add { base.TextChanged += value; }
1696                         remove { base.TextChanged -= value; }
1697                 }
1698
1699                 static object DrawItemEvent = new object ();
1700                 static object SelectedIndexChangedEvent = new object ();
1701
1702                 public event DrawItemEventHandler DrawItem {
1703                         add { Events.AddHandler (DrawItemEvent, value); }
1704                         remove { Events.RemoveHandler (DrawItemEvent, value); }
1705                 }
1706
1707                 public event EventHandler SelectedIndexChanged {
1708                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
1709                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
1710                 }
1711                 
1712 #if NET_2_0
1713                 static object SelectedEvent = new object ();
1714                 
1715                 public event TabControlEventHandler Selected {
1716                         add { Events.AddHandler (SelectedEvent, value); }
1717                         remove { Events.RemoveHandler (SelectedEvent, value); }
1718                 }
1719
1720                 static object DeselectedEvent = new object ();
1721
1722                 public event TabControlEventHandler Deselected
1723                 {
1724                         add { Events.AddHandler (DeselectedEvent, value); }
1725                         remove { Events.RemoveHandler (DeselectedEvent, value); }
1726                 }
1727
1728                 static object SelectingEvent = new object ();
1729
1730                 public event TabControlCancelEventHandler Selecting
1731                 {
1732                         add { Events.AddHandler (SelectingEvent, value); }
1733                         remove { Events.RemoveHandler (SelectingEvent, value); }
1734                 }
1735
1736                 static object DeselectingEvent = new object ();
1737
1738                 public event TabControlCancelEventHandler Deselecting
1739                 {
1740                         add { Events.AddHandler (DeselectingEvent, value); }
1741                         remove { Events.RemoveHandler (DeselectingEvent, value); }
1742                 }
1743
1744                 static object RightToLeftLayoutChangedEvent = new object ();
1745                 public event EventHandler RightToLeftLayoutChanged
1746                 {
1747                         add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
1748                         remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
1749                 }
1750 #endif
1751                 #endregion      // Events
1752
1753
1754                 #region Class TaControl.ControlCollection
1755 #if NET_2_0
1756                 [ComVisible (false)]
1757 #endif
1758                 public new class ControlCollection : System.Windows.Forms.Control.ControlCollection {
1759
1760                         private TabControl owner;
1761
1762                         public ControlCollection (TabControl owner) : base (owner)
1763                         {
1764                                 this.owner = owner;
1765                         }
1766
1767                         public override void Add (Control value)
1768                         {
1769                                 TabPage page = value as TabPage;
1770                                 if (page == null)
1771                                         throw new ArgumentException ("Cannot add " +
1772                                                 value.GetType ().Name + " to TabControl. " +
1773                                                 "Only TabPages can be directly added to TabControls.");
1774
1775                                 page.SetVisible (false);
1776                                 base.Add (value);
1777                                 if (owner.TabCount == 1 && owner.selected_index < 0)
1778                                         owner.SelectedIndex = 0;
1779                                 owner.Redraw ();
1780                         }
1781
1782                         public override void Remove (Control value)
1783                         {
1784                                 bool change_index = false;
1785                                 
1786                                 TabPage page = value as TabPage;
1787                                 if (page != null && owner.Controls.Contains (page)) {
1788                                         int index = owner.IndexForTabPage (page);
1789                                         if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1)
1790                                                 change_index = true;
1791                                 }
1792                                 
1793                                 base.Remove (value);
1794                                 
1795                                 // We don't want to raise SelectedIndexChanged until after we
1796                                 // have removed from the collection, so TabCount will be
1797                                 // correct for the user.
1798                                 if (change_index && Count > 0) {
1799                                         // Clear the selected index internally, to avoid trying to access the previous
1800                                         // selected tab when setting the new one - this is what .net seems to do
1801                                         int prev_selected_index = owner.SelectedIndex;
1802                                         owner.selected_index = -1;
1803
1804                                         owner.SelectedIndex = --prev_selected_index;
1805                                 } else if (change_index) {
1806                                         owner.selected_index = -1;
1807                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
1808                                 } else
1809                                         owner.Redraw ();
1810                         }
1811                 }
1812                 #endregion      // Class TabControl.ControlCollection
1813
1814                 #region Class TabPage.TabPageCollection
1815                 public class TabPageCollection  : IList, ICollection, IEnumerable {
1816
1817                         private TabControl owner;
1818
1819                         public TabPageCollection (TabControl owner)
1820                         {
1821                                 if (owner == null)
1822                                         throw new ArgumentNullException ("Value cannot be null.");
1823                                 this.owner = owner;
1824                         }
1825
1826                         [Browsable(false)]
1827                         public int Count {
1828                                 get { return owner.Controls.Count; }
1829                         }
1830
1831                         public bool IsReadOnly {
1832                                 get { return false; }
1833                         }
1834
1835                         public virtual TabPage this [int index] {
1836                                 get {
1837                                         return owner.GetTab (index);
1838                                 }
1839                                 set {
1840                                         owner.SetTab (index, value);
1841                                 }
1842                         }
1843 #if NET_2_0
1844                         public virtual TabPage this [string key] {
1845                                 get {
1846                                         if (string.IsNullOrEmpty (key))
1847                                                 return null;
1848
1849                                         int index = this.IndexOfKey (key);
1850                                         if (index < 0 || index >= this.Count)
1851                                                 return null;
1852                                         
1853                                         return this[index];
1854                                 }
1855                         }
1856 #endif
1857
1858                         internal int this[TabPage tabPage] {
1859                                 get {
1860                                         if (tabPage == null)
1861                                                 return -1;
1862
1863                                         for (int i = 0; i < this.Count; i++)
1864                                                 if (this[i].Equals (tabPage))
1865                                                         return i;
1866
1867                                         return -1;
1868                                 }
1869                         }
1870
1871                         bool ICollection.IsSynchronized {
1872                                 get { return false; }
1873                         }
1874
1875                         object ICollection.SyncRoot {
1876                                 get { return this; }
1877                         }
1878
1879                         bool IList.IsFixedSize {
1880                                 get { return false; }
1881                         }
1882
1883                         object IList.this [int index] {
1884                                 get {
1885                                         return owner.GetTab (index);
1886                                 }
1887                                 set {
1888                                         owner.SetTab (index, (TabPage) value);
1889                                 }
1890                         }
1891
1892                         public void Add (TabPage value)
1893                         {
1894                                 if (value == null)
1895                                         throw new ArgumentNullException ("Value cannot be null.");
1896                                 owner.Controls.Add (value);
1897                         }
1898
1899 #if NET_2_0
1900                         public void Add (string text)
1901                         {
1902                                 TabPage page = new TabPage (text);
1903                                 this.Add (page);
1904                         }
1905
1906                         public void Add (string key, string text)
1907                         {
1908                                 TabPage page = new TabPage (text);
1909                                 page.Name = key;
1910                                 this.Add (page);
1911                         }
1912
1913                         public void Add (string key, string text, int imageIndex)
1914                         {
1915                                 TabPage page = new TabPage (text);
1916                                 page.Name = key;
1917                                 page.ImageIndex = imageIndex;
1918                                 this.Add (page);
1919                         }
1920
1921                         // .Net sets the ImageKey, but does not show the image when this is used
1922                         public void Add (string key, string text, string imageKey)
1923                         {
1924                                 TabPage page = new TabPage (text);
1925                                 page.Name = key;
1926                                 page.ImageKey = imageKey;
1927                                 this.Add (page);
1928                         }
1929 #endif
1930
1931                         public void AddRange (TabPage [] pages)
1932                         {
1933                                 if (pages == null)
1934                                         throw new ArgumentNullException ("Value cannot be null.");
1935                                 owner.Controls.AddRange (pages);
1936                         }
1937
1938                         public virtual void Clear ()
1939                         {
1940                                 owner.Controls.Clear ();
1941                                 owner.Invalidate ();
1942                         }
1943
1944                         public bool Contains (TabPage page)
1945                         {
1946                                 if (page == null)
1947                                         throw new ArgumentNullException ("Value cannot be null.");
1948                                 return owner.Controls.Contains (page);
1949                         }
1950
1951 #if NET_2_0
1952                         public virtual bool ContainsKey (string key)
1953                         {
1954                                 int index = this.IndexOfKey (key);
1955                                 return (index >= 0 && index < this.Count);
1956                         }
1957 #endif
1958
1959                         public IEnumerator GetEnumerator ()
1960                         {
1961                                 return owner.Controls.GetEnumerator ();
1962                         }
1963
1964                         public int IndexOf (TabPage page)
1965                         {
1966                                 return owner.Controls.IndexOf (page);
1967                         }
1968
1969 #if NET_2_0
1970                         public virtual int IndexOfKey(string key)
1971                         {
1972                                 if (string.IsNullOrEmpty (key))
1973                                         return -1;
1974
1975                                 for (int i = 0; i < this.Count; i++) {
1976                                         if (string.Compare (this[i].Name, key, true, 
1977                                                 System.Globalization.CultureInfo.InvariantCulture) == 0) {
1978                                                 return i;
1979                                         }
1980                                 }
1981
1982                                 return -1;
1983                         }
1984 #endif
1985
1986                         public void Remove (TabPage value)
1987                         {
1988                                 owner.Controls.Remove (value);
1989                                 owner.Invalidate ();
1990                         }
1991
1992                         public void RemoveAt (int index)
1993                         {
1994                                 owner.Controls.RemoveAt (index);
1995                                 owner.Invalidate ();
1996                         }
1997
1998 #if NET_2_0
1999                         public virtual void RemoveByKey (string key)
2000                         {
2001                                 int index = this.IndexOfKey (key);
2002                                 if (index >= 0 && index < this.Count)
2003                                         this.RemoveAt (index);
2004                         }
2005 #endif
2006
2007                         void ICollection.CopyTo (Array dest, int index)
2008                         {
2009                                 owner.Controls.CopyTo (dest, index);
2010                         }
2011
2012                         int IList.Add (object value)
2013                         {
2014                                 TabPage page = value as TabPage;
2015                                 if (value == null)
2016                                         throw new ArgumentException ("value");
2017                                 owner.Controls.Add (page);
2018                                 return owner.Controls.IndexOf (page);
2019                         }
2020
2021                         bool IList.Contains (object page)
2022                         {
2023                                 TabPage tabPage = page as TabPage;
2024                                 if (tabPage == null)
2025                                         return false;
2026                                 return Contains (tabPage);
2027                         }
2028
2029                         int IList.IndexOf (object page)
2030                         {
2031                                 TabPage tabPage = page as TabPage;
2032                                 if (tabPage == null)
2033                                         return -1;
2034                                 return IndexOf (tabPage);
2035                         }
2036
2037 #if NET_2_0
2038                         void IList.Insert (int index, object tabPage)
2039 #else
2040                         void IList.Insert (int index, object value)
2041 #endif
2042                         {
2043                                 throw new NotSupportedException ();
2044                         }
2045
2046 #if NET_2_0
2047                         public void Insert (int index, string text)
2048                         {
2049                                 owner.InsertTab (index, new TabPage (text));
2050                         }
2051                         
2052                         public void Insert (int index, TabPage tabPage)
2053                         {
2054                                 owner.InsertTab (index, tabPage);
2055                         }
2056
2057                         public void Insert (int index, string key, string text)
2058                         {
2059                                 TabPage page = new TabPage(text);
2060                                 page.Name = key;
2061                                 owner.InsertTab (index, page);
2062                         }
2063
2064                         public void Insert (int index, string key, string text, int imageIndex) 
2065                         {
2066                                 TabPage page = new TabPage(text);
2067                                 page.Name = key;
2068                                 owner.InsertTab (index, page);
2069                                 page.ImageIndex = imageIndex;
2070                         }
2071
2072                         public void Insert (int index, string key, string text, string imageKey) 
2073                         {
2074                                 TabPage page = new TabPage(text);
2075                                 page.Name = key;
2076                                 owner.InsertTab (index, page);
2077                                 page.ImageKey = imageKey;
2078                         }
2079 #endif
2080                         void IList.Remove (object value)
2081                         {
2082                                 TabPage page = value as TabPage;
2083                                 if (page == null)
2084                                         return;
2085                                 Remove ((TabPage) value);
2086                         }
2087                 }
2088                 #endregion      // Class TabPage.TabPageCollection
2089         }
2090 }
2091
2092