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