2009-06-12 Bill Holmes <billholmes54@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                         if (ke.KeyCode == Keys.Tab && (ke.KeyData & Keys.Control) != 0) {
823                                 if ((ke.KeyData & Keys.Shift) == 0)
824                                         SelectedIndex = (SelectedIndex + 1) % TabCount;
825                                 else
826                                         SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount;
827                                 ke.Handled = true;
828                         } else if (ke.KeyCode == Keys.Home) {
829                                 SelectedIndex = 0;
830                                 ke.Handled = true;
831                         } else if (ke.KeyCode == Keys.End) {
832                                 SelectedIndex = TabCount - 1;
833                                 ke.Handled = true;
834                         } else if (NavigateTabs (ke.KeyCode))
835                                 ke.Handled = true;
836
837                         base.OnKeyDown (ke);
838                 }
839
840                 protected override bool IsInputKey (Keys keyData)
841                 {
842                         switch (keyData & Keys.KeyCode) {
843                         case Keys.Home:
844                         case Keys.End:
845                         case Keys.Left:
846                         case Keys.Right:
847                         case Keys.Up:
848                         case Keys.Down:
849                                 return true;
850                         }
851                         return base.IsInputKey (keyData);
852                 }
853                 
854                 private bool NavigateTabs (Keys keycode)
855                 {
856                         bool move_left = false;
857                         bool move_right = false;
858                         
859                         if (alignment == TabAlignment.Bottom || alignment == TabAlignment.Top) {
860                                 if (keycode == Keys.Left)
861                                         move_left = true;
862                                 else if (keycode == Keys.Right)
863                                         move_right = true;
864                         } else {
865                                 if (keycode == Keys.Up)
866                                         move_left = true;
867                                 else if (keycode == Keys.Down)
868                                         move_right = true;
869                         }
870                                 
871                         if (move_left) {
872                                 if (SelectedIndex > 0) {
873                                         SelectedIndex--;
874                                         return true;
875                                 }
876                         }
877                         
878                         if (move_right) {
879                                 if (SelectedIndex < TabCount - 1) {
880                                         SelectedIndex++;
881                                         return true;
882                                 }
883                         }
884                         
885                         return false;
886                 }
887                 #endregion
888
889                 #region Pages Collection
890                 protected void RemoveAll ()
891                 {
892                         Controls.Clear ();
893                 }
894
895                 protected virtual object [] GetItems ()
896                 {
897                         TabPage [] pages = new TabPage [Controls.Count];
898                         Controls.CopyTo (pages, 0);
899                         return pages;
900                 }
901
902                 protected virtual object [] GetItems (Type baseType)
903                 {
904                         object[] pages = (object[])Array.CreateInstance (baseType, Controls.Count);
905                         Controls.CopyTo (pages, 0);
906                         return pages;
907                 }
908                 #endregion
909
910 #if NET_2_0
911                 protected void UpdateTabSelection (bool updateFocus)
912 #else
913                 protected void UpdateTabSelection (bool uiselected)
914 #endif
915                 {
916                         ResizeTabPages ();
917                 }
918
919                 protected string GetToolTipText (object item)
920                 {
921                         TabPage page = (TabPage) item;
922                         return page.ToolTipText;
923                 }
924
925                 protected override void WndProc (ref Message m)
926                 {
927                         switch ((Msg)m.Msg) {
928                         case Msg.WM_SETFOCUS:
929                                 if (selected_index == -1 && this.TabCount > 0)
930                                         this.SelectedIndex = 0;
931                                 if (selected_index != -1)
932                                         Invalidate(GetTabRect(selected_index));
933                                 base.WndProc (ref m);
934                                 break;
935                         case Msg.WM_KILLFOCUS:
936                                 if (selected_index != -1)
937                                         Invalidate(GetTabRect(selected_index));
938                                 base.WndProc (ref m);
939                                 break;
940                         default:
941                                 base.WndProc (ref m);
942                                 break;
943                         }
944                 }
945
946                 #endregion      // Protected Instance Methods
947
948                 #region Internal & Private Methods
949                 private bool CanScrollRight {
950                         get {
951                                 return (slider_pos < TabCount - 1);
952                         }
953                 }
954
955                 private bool CanScrollLeft {
956                         get { return slider_pos > 0; }
957                 }
958
959                 private void MouseDownHandler (object sender, MouseEventArgs e)
960                 {
961                         if ((e.Button & MouseButtons.Left) == 0)
962                                 return;
963
964                         if (ShowSlider) {
965                                 Rectangle right = RightScrollButtonArea;
966                                 Rectangle left = LeftScrollButtonArea;
967                                 if (right.Contains (e.X, e.Y)) {
968                                         right_slider_state = PushButtonState.Pressed;
969                                         if (CanScrollRight) {
970                                                 slider_pos++;
971                                                 SizeTabs ();
972
973 #if NET_2_0
974                                                 // UIA Framework Event: Horizontally Scrolled
975                                                 OnUIAHorizontallyScrolled (EventArgs.Empty);
976 #endif
977
978                                                 switch (this.Alignment) {
979                                                         case TabAlignment.Top:
980                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
981                                                                 break;
982                                                         case TabAlignment.Bottom:
983                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
984                                                                 break;
985                                                         case TabAlignment.Left:
986                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
987                                                                 break;
988                                                         case TabAlignment.Right:
989                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
990                                                                 break;
991                                                 }
992                                                 
993                                         } else {
994                                                 Invalidate (right);
995                                         }
996                                         return;
997                                 } else if (left.Contains (e.X, e.Y)) {
998                                         left_slider_state = PushButtonState.Pressed;
999                                         if (CanScrollLeft) {
1000                                                 slider_pos--;
1001                                                 SizeTabs ();
1002
1003 #if NET_2_0
1004                                                 // UIA Framework Event: Horizontally Scrolled
1005                                                 OnUIAHorizontallyScrolled (EventArgs.Empty);
1006 #endif
1007
1008                                                 switch (this.Alignment) {
1009                                                         case TabAlignment.Top:
1010                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
1011                                                                 break;
1012                                                         case TabAlignment.Bottom:
1013                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
1014                                                                 break;
1015                                                         case TabAlignment.Left:
1016                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
1017                                                                 break;
1018                                                         case TabAlignment.Right:
1019                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
1020                                                                 break;
1021                                                 }
1022                                         } else {
1023                                                 Invalidate (left);
1024                                         }
1025                                         return;
1026                                 }
1027                         }
1028
1029                         int count = Controls.Count;
1030                         for (int i = SliderPos; i < count; i++) {
1031                                 if (!GetTabRect (i).Contains (e.X, e.Y))
1032                                         continue;
1033                                 SelectedIndex = i;
1034                                 mouse_down_on_a_tab_page = true;
1035                                 break;
1036                         }
1037                 }
1038
1039                 private void MouseUpHandler (object sender, MouseEventArgs e)
1040                 {
1041                         mouse_down_on_a_tab_page = false;
1042                         if (ShowSlider && (left_slider_state == PushButtonState.Pressed || right_slider_state == PushButtonState.Pressed)) {
1043                                 Rectangle invalid;
1044                                 if (left_slider_state == PushButtonState.Pressed) {
1045                                         invalid = LeftScrollButtonArea;
1046                                         left_slider_state = GetScrollButtonState (invalid, e.Location);
1047                                 } else {
1048                                         invalid = RightScrollButtonArea;
1049                                         right_slider_state = GetScrollButtonState (invalid, e.Location);
1050                                 }
1051                                 Invalidate (invalid);
1052                         }
1053                 }
1054
1055                 bool HasHotElementStyles {
1056                         get {
1057                                 return ThemeElements.CurrentTheme.TabControlPainter.HasHotElementStyles (this);
1058                         }
1059                 }
1060
1061                 Rectangle LeftScrollButtonArea {
1062                         get {
1063                                 return ThemeElements.CurrentTheme.TabControlPainter.GetLeftScrollRect (this);
1064                         }
1065                 }
1066
1067                 Rectangle RightScrollButtonArea {
1068                         get {
1069                                 return ThemeElements.CurrentTheme.TabControlPainter.GetRightScrollRect (this);
1070                         }
1071                 }
1072
1073                 static PushButtonState GetScrollButtonState (Rectangle scrollButtonArea, Point cursorLocation)
1074                 {
1075                         return scrollButtonArea.Contains (cursorLocation) ? PushButtonState.Hot : PushButtonState.Normal;
1076                 }
1077
1078                 private void SizeChangedHandler (object sender, EventArgs e)
1079                 {
1080                         Redraw ();
1081                 }
1082
1083                 internal int IndexForTabPage (TabPage page)
1084                 {
1085                         for (int i = 0; i < tab_pages.Count; i++) {
1086                                 if (page == tab_pages [i])
1087                                         return i;
1088                         }
1089                         return -1;
1090                 }
1091
1092                 private void ResizeTabPages ()
1093                 {
1094                         CalcTabRows ();
1095                         SizeTabs ();
1096                         Rectangle r = DisplayRectangle;
1097                         foreach (TabPage page in Controls) {
1098                                 page.Bounds = r;
1099                         }
1100                 }
1101
1102                 private int MinimumTabWidth {
1103                         get {
1104                                 return ThemeEngine.Current.TabControlMinimumTabWidth;
1105                         }
1106                 }
1107
1108                 private Size TabSpacing {
1109                         get {
1110                                 return ThemeEngine.Current.TabControlGetSpacing (this);
1111                         }
1112                 }
1113
1114                 private void CalcTabRows ()
1115                 {
1116                         switch (Alignment) {
1117                         case TabAlignment.Right:
1118                         case TabAlignment.Left:
1119                                 CalcTabRows (Height);
1120                                 break;
1121                         default:
1122                                 CalcTabRows (Width);
1123                                 break;
1124                         }
1125                 }
1126
1127                 private void CalcTabRows (int row_width)
1128                 {
1129                         int xpos = 0;
1130                         int ypos = 0;
1131                         Size spacing = TabSpacing;
1132
1133                         if (TabPages.Count > 0)
1134                                 row_count = 1;
1135                         show_slider = false;
1136                         
1137                         for (int i = 0; i < TabPages.Count; i++) {
1138                                 TabPage page = TabPages [i];
1139                                 int aux = 0;
1140                                 SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, 0, ref aux, true);
1141                         }
1142
1143                         if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow)
1144                                 DropRow (TabPages [SelectedIndex].Row);
1145                 }
1146
1147                 private int BottomRow {
1148                         get { return 1; }
1149                 }
1150
1151                 private int Direction
1152                 {
1153                         get {
1154                                 return 1;
1155                         }
1156                 }
1157
1158                 private void DropRow (int row)
1159                 {
1160                         if (Appearance != TabAppearance.Normal)
1161                                 return;
1162
1163                         int bottom = BottomRow;
1164                         int direction = Direction;
1165
1166                         foreach (TabPage page in TabPages) {
1167                                 if (page.Row == row) {
1168                                         page.Row = bottom;
1169                                 } else if (direction == 1 && page.Row < row) {
1170                                         page.Row += direction;
1171                                 } else if (direction == -1 && page.Row > row) {
1172                                         page.Row += direction;
1173                                 }
1174                         }
1175                 }
1176
1177                 private int CalcYPos ()
1178                 {
1179                         if (Alignment == TabAlignment.Bottom || Alignment == TabAlignment.Left)
1180                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom;
1181
1182                         if (Appearance == TabAppearance.Normal)
1183                                 return this.ClientRectangle.Y + ThemeEngine.Current.TabControlSelectedDelta.Y;
1184
1185                         return this.ClientRectangle.Y;
1186
1187                 }
1188
1189                 private int CalcXPos ()
1190                 {
1191                         if (Alignment == TabAlignment.Right)
1192                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Right;
1193
1194                         if (Appearance == TabAppearance.Normal)
1195                                 return this.ClientRectangle.X + ThemeEngine.Current.TabControlSelectedDelta.X;
1196
1197                         return this.ClientRectangle.X;
1198                 }
1199
1200                 private void SizeTabs ()
1201                 {
1202                         switch (Alignment) {
1203                         case TabAlignment.Right:
1204                         case TabAlignment.Left:
1205                                 SizeTabs (Height, true);
1206                                 break;
1207                         default:
1208                                 SizeTabs (Width, false);
1209                                 break;
1210                         }
1211                 }
1212                 
1213                 private void SizeTabs (int row_width, bool vertical)
1214                 {
1215                         int ypos = 0;
1216                         int xpos = 0;
1217                         int prev_row = 1;
1218                         Size spacing = TabSpacing;
1219                         int begin_prev = 0;
1220
1221                         if (TabPages.Count == 0)
1222                                 return;
1223
1224                         prev_row = TabPages [0].Row;
1225
1226                         // Reset the slider position if the slider isn't needed
1227                         // anymore (ie window size was increased so all tabs are visible)
1228                         if (!show_slider)
1229                                 slider_pos = 0;
1230                         else {
1231                                 // set X = -1 for marking tabs that are not visible due to scrolling
1232                                 for (int i = 0; i < slider_pos; i++) {
1233                                         TabPage page = TabPages[i];
1234                                         Rectangle x = page.TabBounds;
1235                                         x.X = -1;
1236                                         page.TabBounds = x;
1237                                 }
1238                         }
1239                         
1240                         for (int i = slider_pos; i < TabPages.Count; i++) {
1241                                 TabPage page = TabPages[i];
1242                                 SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false);
1243                                 prev_row = page.Row;
1244                         }
1245
1246                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1247                                 FillRow (begin_prev, TabPages.Count - 1,
1248                                                 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), 
1249                                                 spacing, vertical);
1250                         }
1251
1252                         if (SelectedIndex != -1) {
1253                                 ExpandSelected (TabPages [SelectedIndex], 0, row_width - 1);
1254                         }
1255                 }
1256                 
1257                 private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos, 
1258                                                                 Size spacing, int prev_row, ref int begin_prev, bool widthOnly) 
1259                 {                               
1260                         int width, height = 0;
1261
1262                         if (SizeMode == TabSizeMode.Fixed) {
1263                                 width = item_size.Width;
1264                         } else {                        
1265                                 width = MeasureStringWidth (DeviceContext, page.Text, Font);
1266                                 width += (Padding.X * 2) + 2;
1267
1268                                 if (ImageList != null && page.ImageIndex >= 0 && page.ImageIndex < ImageList.Images.Count) {
1269                                         width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X;
1270
1271                                         int image_size = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y;
1272                                         if (item_size.Height < image_size)
1273                                                 item_size.Height = image_size;
1274                                 }
1275                         }
1276
1277                         height = item_size.Height - ThemeEngine.Current.TabControlSelectedDelta.Height; // full height only for selected tab
1278
1279                         if (width < MinimumTabWidth)
1280                                 width = MinimumTabWidth;
1281
1282                         if (i == SelectedIndex)
1283                                 width += ThemeEngine.Current.TabControlSelectedSpacing;
1284                         
1285                         if (widthOnly) {
1286                                 page.TabBounds = new Rectangle (xpos, 0, width, 0);
1287                                 page.Row = row_count;
1288                                 if (xpos + width > row_width && multiline) {
1289                                         xpos = 0;
1290                                         row_count++;
1291                                 } else if (xpos + width > row_width) {
1292                                         show_slider = true;     
1293                                 }
1294                                 if (i == selected_index && show_slider) {
1295                                         for (int j = i-1; j >= 0; j--) {
1296                                                 if (TabPages [j].TabBounds.Left < xpos + width - row_width) {
1297                                                         slider_pos = j+1;
1298                                                         break;
1299                                                 }
1300                                         }
1301                                 }
1302                         } else {
1303                                 if (page.Row != prev_row) {
1304                                         xpos = 0;
1305                                 }
1306
1307                                 switch (Alignment) {
1308                                         case TabAlignment.Top:
1309                                                 page.TabBounds = new Rectangle (
1310                                                         xpos + CalcXPos (),
1311                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1312                                                         width, 
1313                                                         height);
1314                                                 break;
1315                                         case TabAlignment.Bottom:
1316                                                 page.TabBounds = new Rectangle (
1317                                                         xpos + CalcXPos (),
1318                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1319                                                         width, 
1320                                                         height);
1321                                                 break;
1322                                         case TabAlignment.Left:
1323                                                 if (Appearance == TabAppearance.Normal) {
1324                                                         // tab rows are positioned right to left
1325                                                         page.TabBounds = new Rectangle (
1326                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1327                                                                 xpos,
1328                                                                 height, 
1329                                                                 width);
1330                                                 } else {
1331                                                         // tab rows are positioned left to right
1332                                                         page.TabBounds = new Rectangle (
1333                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1334                                                                 xpos,
1335                                                                 height, 
1336                                                                 width);
1337                                                 }
1338
1339                                                 break;
1340                                         case TabAlignment.Right:
1341                                                 if (Appearance == TabAppearance.Normal) {
1342                                                         // tab rows are positioned left to right
1343                                                         page.TabBounds = new Rectangle (
1344                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1345                                                                 xpos,
1346                                                                 height, 
1347                                                                 width);
1348                                                 } else {
1349                                                         // tab rows are positioned right to left
1350                                                         page.TabBounds = new Rectangle (
1351                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1352                                                                 xpos,
1353                                                                 height, 
1354                                                                 width);
1355                                                 }
1356
1357                                                 break;
1358                                 }
1359                         
1360                                 if (page.Row != prev_row) {
1361                                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1362                                                 bool vertical = alignment == TabAlignment.Right || alignment == TabAlignment.Left;
1363                                                 int offset = vertical ? TabPages [i - 1].TabBounds.Bottom : TabPages [i - 1].TabBounds.Right;
1364                                                 FillRow (begin_prev, i - 1, ((row_width - offset) / (i - begin_prev)), spacing,
1365                                                         vertical);
1366                                         }
1367                                         begin_prev = i;
1368                                 }       
1369                         }
1370
1371                         xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing;
1372                 }
1373
1374                 private void FillRow (int start, int end, int amount, Size spacing, bool vertical) 
1375                 {
1376                         if (vertical)
1377                                 FillRowV (start, end, amount, spacing);
1378                         else
1379                                 FillRow (start, end, amount, spacing);
1380                 }
1381
1382                 private void FillRow (int start, int end, int amount, Size spacing)
1383                 {
1384                         int xpos = TabPages [start].TabBounds.Left;
1385                         for (int i = start; i <= end; i++) {
1386                                 TabPage page = TabPages [i];
1387                                 int left = xpos;
1388                                 int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
1389
1390                                 page.TabBounds = new Rectangle (left, page.TabBounds.Top,
1391                                                 width, page.TabBounds.Height);
1392                                 xpos = page.TabBounds.Right + 1 + spacing.Width;
1393                         }
1394                 }
1395
1396                 private void FillRowV (int start, int end, int amount, Size spacing)
1397                 {
1398                         int ypos = TabPages [start].TabBounds.Top;
1399                         for (int i = start; i <= end; i++) {
1400                                 TabPage page = TabPages [i];
1401                                 int top = ypos;
1402                                 int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
1403
1404                                 page.TabBounds = new Rectangle (page.TabBounds.Left, top,
1405                                                 page.TabBounds.Width, height);
1406                                 ypos = page.TabBounds.Bottom + 1;
1407                         }
1408                 }
1409
1410                 private void ExpandSelected (TabPage page, int left_edge, int right_edge)
1411                 {
1412                         if (Appearance != TabAppearance.Normal)
1413                                 return;
1414
1415                         Rectangle r = page.TabBounds;
1416                         switch (Alignment) {
1417                                 case TabAlignment.Top:
1418                                 case TabAlignment.Left:
1419                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1420                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1421                                         break;
1422                                 case TabAlignment.Bottom:
1423                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1424                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1425                                         break;
1426                                 case TabAlignment.Right:
1427                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1428                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1429                                         break;
1430                         }
1431
1432                         r.Width += ThemeEngine.Current.TabControlSelectedDelta.Width;
1433                         r.Height += ThemeEngine.Current.TabControlSelectedDelta.Height;
1434                         if (r.Left < left_edge)
1435                                 r.X = left_edge;
1436                         // Adjustment can't be used for right alignment, since it is
1437                         // the only one that has a different X origin than 0
1438                         if (r.Right > right_edge && SizeMode != TabSizeMode.Normal &&
1439                                         alignment != TabAlignment.Right)
1440                                 r.Width = right_edge - r.X;
1441                         page.TabBounds = r;
1442                 }
1443
1444                 private void Draw (Graphics dc, Rectangle clip)
1445                 {
1446                         ThemeEngine.Current.DrawTabControl (dc, clip, this);
1447                 }
1448
1449                 private TabPage GetTab (int index)
1450                 {
1451                         return Controls [index] as TabPage;
1452                 }
1453
1454                 private void SetTab (int index, TabPage value)
1455                 {
1456                         if (!tab_pages.Contains (value)) {
1457                                 this.Controls.Add (value);
1458                         }
1459                         this.Controls.RemoveAt (index);
1460                         this.Controls.SetChildIndex (value, index);
1461                         Redraw ();
1462                 }
1463 #if NET_2_0
1464                 private void InsertTab (int index, TabPage value)
1465                 {
1466                         if (!tab_pages.Contains (value)) {
1467                                 this.Controls.Add (value);
1468                         }
1469                         this.Controls.SetChildIndex (value, index);
1470                         Redraw ();
1471                 }
1472 #endif
1473                 internal void Redraw ()
1474                 {
1475                         if (!IsHandleCreated)
1476                                 return;
1477
1478                         ResizeTabPages ();
1479                         Refresh ();
1480                 }
1481
1482                 private int MeasureStringWidth (Graphics graphics, string text, Font font) 
1483                 {
1484                         if (text == String.Empty)
1485                                 return 0;
1486                         StringFormat format = new StringFormat();
1487                         RectangleF rect = new RectangleF(0, 0, 1000, 1000);
1488                         CharacterRange[] ranges = { new CharacterRange(0, text.Length) };
1489                         Region[] regions = new Region[1];
1490
1491                         format.SetMeasurableCharacterRanges(ranges);
1492                         format.FormatFlags = StringFormatFlags.NoClip;
1493                         format.FormatFlags |= StringFormatFlags.NoWrap;
1494                         regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format);
1495                         rect = regions[0].GetBounds(graphics);
1496
1497                         return (int)(rect.Width);
1498                 }
1499
1500                 void OnMouseMove (object sender, MouseEventArgs e)
1501                 {
1502                         if (!mouse_down_on_a_tab_page && ShowSlider) {
1503                                 if (LeftSliderState == PushButtonState.Pressed ||
1504                                         RightSliderState == PushButtonState.Pressed)
1505                                         return;
1506                                 if (LeftScrollButtonArea.Contains (e.Location)) {
1507                                         LeftSliderState = PushButtonState.Hot;
1508                                         RightSliderState = PushButtonState.Normal;
1509                                         EnteredTabPage = null;
1510                                         return;
1511                                 }
1512                                 if (RightScrollButtonArea.Contains (e.Location)) {
1513                                         RightSliderState = PushButtonState.Hot;
1514                                         LeftSliderState = PushButtonState.Normal;
1515                                         EnteredTabPage = null;
1516                                         return;
1517                                 }
1518                                 LeftSliderState = PushButtonState.Normal;
1519                                 RightSliderState = PushButtonState.Normal;
1520                         }
1521                         if (EnteredTabPage != null && EnteredTabPage.TabBounds.Contains (e.Location))
1522                                 return;
1523                         for (int index = 0; index < TabCount; index++) {
1524                                 TabPage tab_page = TabPages[index];
1525                                 if (tab_page.TabBounds.Contains (e.Location)) {
1526                                         EnteredTabPage = tab_page;
1527                                         return;
1528                                 }
1529                         }
1530                         EnteredTabPage = null;
1531                 }
1532
1533                 void OnMouseLeave (object sender, EventArgs e)
1534                 {
1535                         if (ShowSlider) {
1536                                 LeftSliderState = PushButtonState.Normal;
1537                                 RightSliderState = PushButtonState.Normal;
1538                         }
1539                         EnteredTabPage = null;
1540                 }
1541                 #endregion      // Internal & Private Methods
1542
1543                 #region Events
1544                 [Browsable(false)]
1545                 [EditorBrowsable(EditorBrowsableState.Never)]
1546                 public new event EventHandler BackColorChanged {
1547                         add { base.BackColorChanged += value; }
1548                         remove { base.BackColorChanged -= value; }
1549                 }
1550
1551                 [Browsable(false)]
1552                 [EditorBrowsable(EditorBrowsableState.Never)]
1553                 public new event EventHandler BackgroundImageChanged {
1554                         add { base.BackgroundImageChanged += value; }
1555                         remove { base.BackgroundImageChanged -= value; }
1556                 }
1557
1558 #if NET_2_0
1559                 [Browsable (false)]
1560                 [EditorBrowsable (EditorBrowsableState.Never)]
1561                 public new event EventHandler BackgroundImageLayoutChanged
1562                 {
1563                         add { base.BackgroundImageLayoutChanged += value; }
1564                         remove { base.BackgroundImageLayoutChanged -= value; }
1565                 }
1566 #endif
1567
1568                 [Browsable(false)]
1569                 [EditorBrowsable(EditorBrowsableState.Never)]
1570                 public new event EventHandler ForeColorChanged {
1571                         add { base.ForeColorChanged += value; }
1572                         remove { base.ForeColorChanged -= value; }
1573                 }
1574
1575                 [Browsable(false)]
1576                 [EditorBrowsable(EditorBrowsableState.Never)]
1577                 public new event PaintEventHandler Paint {
1578                         add { base.Paint += value; }
1579                         remove { base.Paint -= value; }
1580                 }
1581
1582                 [Browsable(false)]
1583                 [EditorBrowsable(EditorBrowsableState.Never)]
1584                 public new event EventHandler TextChanged {
1585                         add { base.TextChanged += value; }
1586                         remove { base.TextChanged -= value; }
1587                 }
1588
1589                 static object DrawItemEvent = new object ();
1590                 static object SelectedIndexChangedEvent = new object ();
1591
1592                 public event DrawItemEventHandler DrawItem {
1593                         add { Events.AddHandler (DrawItemEvent, value); }
1594                         remove { Events.RemoveHandler (DrawItemEvent, value); }
1595                 }
1596
1597                 public event EventHandler SelectedIndexChanged {
1598                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
1599                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
1600                 }
1601                 
1602 #if NET_2_0
1603                 static object SelectedEvent = new object ();
1604                 
1605                 public event TabControlEventHandler Selected {
1606                         add { Events.AddHandler (SelectedEvent, value); }
1607                         remove { Events.RemoveHandler (SelectedEvent, value); }
1608                 }
1609
1610                 static object DeselectedEvent = new object ();
1611
1612                 public event TabControlEventHandler Deselected
1613                 {
1614                         add { Events.AddHandler (DeselectedEvent, value); }
1615                         remove { Events.RemoveHandler (DeselectedEvent, value); }
1616                 }
1617
1618                 static object SelectingEvent = new object ();
1619
1620                 public event TabControlCancelEventHandler Selecting
1621                 {
1622                         add { Events.AddHandler (SelectingEvent, value); }
1623                         remove { Events.RemoveHandler (SelectingEvent, value); }
1624                 }
1625
1626                 static object DeselectingEvent = new object ();
1627
1628                 public event TabControlCancelEventHandler Deselecting
1629                 {
1630                         add { Events.AddHandler (DeselectingEvent, value); }
1631                         remove { Events.RemoveHandler (DeselectingEvent, value); }
1632                 }
1633
1634                 static object RightToLeftLayoutChangedEvent = new object ();
1635                 public event EventHandler RightToLeftLayoutChanged
1636                 {
1637                         add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
1638                         remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
1639                 }
1640 #endif
1641                 #endregion      // Events
1642
1643
1644                 #region Class TaControl.ControlCollection
1645 #if NET_2_0
1646                 [ComVisible (false)]
1647 #endif
1648                 public new class ControlCollection : System.Windows.Forms.Control.ControlCollection {
1649
1650                         private TabControl owner;
1651
1652                         public ControlCollection (TabControl owner) : base (owner)
1653                         {
1654                                 this.owner = owner;
1655                         }
1656
1657                         public override void Add (Control value)
1658                         {
1659                                 TabPage page = value as TabPage;
1660                                 if (page == null)
1661                                         throw new ArgumentException ("Cannot add " +
1662                                                 value.GetType ().Name + " to TabControl. " +
1663                                                 "Only TabPages can be directly added to TabControls.");
1664
1665                                 page.SetVisible (false);
1666                                 base.Add (value);
1667                                 if (owner.TabCount == 1 && owner.selected_index < 0)
1668                                         owner.SelectedIndex = 0;
1669                                 owner.Redraw ();
1670                         }
1671
1672                         public override void Remove (Control value)
1673                         {
1674                                 bool change_index = false;
1675                                 
1676                                 TabPage page = value as TabPage;
1677                                 if (page != null && owner.Controls.Contains (page)) {
1678                                         int index = owner.IndexForTabPage (page);
1679                                         if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1)
1680                                                 change_index = true;
1681                                 }
1682                                 
1683                                 base.Remove (value);
1684                                 
1685                                 // We don't want to raise SelectedIndexChanged until after we
1686                                 // have removed from the collection, so TabCount will be
1687                                 // correct for the user.
1688                                 if (change_index && Count > 0) {
1689                                         // Clear the selected index internally, to avoid trying to access the previous
1690                                         // selected tab when setting the new one - this is what .net seems to do
1691                                         int prev_selected_index = owner.SelectedIndex;
1692                                         owner.selected_index = -1;
1693
1694                                         owner.SelectedIndex = --prev_selected_index;
1695                                 } else if (change_index) {
1696                                         owner.selected_index = -1;
1697                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
1698                                 } else
1699                                         owner.Redraw ();
1700                         }
1701                 }
1702                 #endregion      // Class TabControl.ControlCollection
1703
1704                 #region Class TabPage.TabPageCollection
1705                 public class TabPageCollection  : IList, ICollection, IEnumerable {
1706
1707                         private TabControl owner;
1708
1709                         public TabPageCollection (TabControl owner)
1710                         {
1711                                 if (owner == null)
1712                                         throw new ArgumentNullException ("Value cannot be null.");
1713                                 this.owner = owner;
1714                         }
1715
1716                         [Browsable(false)]
1717                         public int Count {
1718                                 get { return owner.Controls.Count; }
1719                         }
1720
1721                         public bool IsReadOnly {
1722                                 get { return false; }
1723                         }
1724
1725                         public virtual TabPage this [int index] {
1726                                 get {
1727                                         return owner.GetTab (index);
1728                                 }
1729                                 set {
1730                                         owner.SetTab (index, value);
1731                                 }
1732                         }
1733 #if NET_2_0
1734                         public virtual TabPage this [string key] {
1735                                 get {
1736                                         if (string.IsNullOrEmpty (key))
1737                                                 return null;
1738
1739                                         int index = this.IndexOfKey (key);
1740                                         if (index < 0 || index >= this.Count)
1741                                                 return null;
1742                                         
1743                                         return this[index];
1744                                 }
1745                         }
1746 #endif
1747
1748                         internal int this[TabPage tabPage] {
1749                                 get {
1750                                         if (tabPage == null)
1751                                                 return -1;
1752
1753                                         for (int i = 0; i < this.Count; i++)
1754                                                 if (this[i].Equals (tabPage))
1755                                                         return i;
1756
1757                                         return -1;
1758                                 }
1759                         }
1760
1761                         bool ICollection.IsSynchronized {
1762                                 get { return false; }
1763                         }
1764
1765                         object ICollection.SyncRoot {
1766                                 get { return this; }
1767                         }
1768
1769                         bool IList.IsFixedSize {
1770                                 get { return false; }
1771                         }
1772
1773                         object IList.this [int index] {
1774                                 get {
1775                                         return owner.GetTab (index);
1776                                 }
1777                                 set {
1778                                         owner.SetTab (index, (TabPage) value);
1779                                 }
1780                         }
1781
1782                         public void Add (TabPage value)
1783                         {
1784                                 if (value == null)
1785                                         throw new ArgumentNullException ("Value cannot be null.");
1786                                 owner.Controls.Add (value);
1787                         }
1788
1789 #if NET_2_0
1790                         public void Add (string text)
1791                         {
1792                                 TabPage page = new TabPage (text);
1793                                 this.Add (page);
1794                         }
1795
1796                         public void Add (string key, string text)
1797                         {
1798                                 TabPage page = new TabPage (text);
1799                                 page.Name = key;
1800                                 this.Add (page);
1801                         }
1802
1803                         public void Add (string key, string text, int imageIndex)
1804                         {
1805                                 TabPage page = new TabPage (text);
1806                                 page.Name = key;
1807                                 page.ImageIndex = imageIndex;
1808                                 this.Add (page);
1809                         }
1810
1811                         // .Net sets the ImageKey, but does not show the image when this is used
1812                         public void Add (string key, string text, string imageKey)
1813                         {
1814                                 TabPage page = new TabPage (text);
1815                                 page.Name = key;
1816                                 page.ImageKey = imageKey;
1817                                 this.Add (page);
1818                         }
1819 #endif
1820
1821                         public void AddRange (TabPage [] pages)
1822                         {
1823                                 if (pages == null)
1824                                         throw new ArgumentNullException ("Value cannot be null.");
1825                                 owner.Controls.AddRange (pages);
1826                         }
1827
1828                         public virtual void Clear ()
1829                         {
1830                                 owner.Controls.Clear ();
1831                                 owner.Invalidate ();
1832                         }
1833
1834                         public bool Contains (TabPage page)
1835                         {
1836                                 if (page == null)
1837                                         throw new ArgumentNullException ("Value cannot be null.");
1838                                 return owner.Controls.Contains (page);
1839                         }
1840
1841 #if NET_2_0
1842                         public virtual bool ContainsKey (string key)
1843                         {
1844                                 int index = this.IndexOfKey (key);
1845                                 return (index >= 0 && index < this.Count);
1846                         }
1847 #endif
1848
1849                         public IEnumerator GetEnumerator ()
1850                         {
1851                                 return owner.Controls.GetEnumerator ();
1852                         }
1853
1854                         public int IndexOf (TabPage page)
1855                         {
1856                                 return owner.Controls.IndexOf (page);
1857                         }
1858
1859 #if NET_2_0
1860                         public virtual int IndexOfKey(string key)
1861                         {
1862                                 if (string.IsNullOrEmpty (key))
1863                                         return -1;
1864
1865                                 for (int i = 0; i < this.Count; i++) {
1866                                         if (string.Compare (this[i].Name, key, true, 
1867                                                 System.Globalization.CultureInfo.InvariantCulture) == 0) {
1868                                                 return i;
1869                                         }
1870                                 }
1871
1872                                 return -1;
1873                         }
1874 #endif
1875
1876                         public void Remove (TabPage value)
1877                         {
1878                                 owner.Controls.Remove (value);
1879                                 owner.Invalidate ();
1880                         }
1881
1882                         public void RemoveAt (int index)
1883                         {
1884                                 owner.Controls.RemoveAt (index);
1885                                 owner.Invalidate ();
1886                         }
1887
1888 #if NET_2_0
1889                         public virtual void RemoveByKey (string key)
1890                         {
1891                                 int index = this.IndexOfKey (key);
1892                                 if (index >= 0 && index < this.Count)
1893                                         this.RemoveAt (index);
1894                         }
1895 #endif
1896
1897                         void ICollection.CopyTo (Array dest, int index)
1898                         {
1899                                 owner.Controls.CopyTo (dest, index);
1900                         }
1901
1902                         int IList.Add (object value)
1903                         {
1904                                 TabPage page = value as TabPage;
1905                                 if (value == null)
1906                                         throw new ArgumentException ("value");
1907                                 owner.Controls.Add (page);
1908                                 return owner.Controls.IndexOf (page);
1909                         }
1910
1911                         bool IList.Contains (object page)
1912                         {
1913                                 TabPage tabPage = page as TabPage;
1914                                 if (tabPage == null)
1915                                         return false;
1916                                 return Contains (tabPage);
1917                         }
1918
1919                         int IList.IndexOf (object page)
1920                         {
1921                                 TabPage tabPage = page as TabPage;
1922                                 if (tabPage == null)
1923                                         return -1;
1924                                 return IndexOf (tabPage);
1925                         }
1926
1927 #if NET_2_0
1928                         void IList.Insert (int index, object tabPage)
1929 #else
1930                         void IList.Insert (int index, object value)
1931 #endif
1932                         {
1933                                 throw new NotSupportedException ();
1934                         }
1935
1936 #if NET_2_0
1937                         public void Insert (int index, string text)
1938                         {
1939                                 owner.InsertTab (index, new TabPage (text));
1940                         }
1941                         
1942                         public void Insert (int index, TabPage tabPage)
1943                         {
1944                                 owner.InsertTab (index, tabPage);
1945                         }
1946
1947                         public void Insert (int index, string key, string text)
1948                         {
1949                                 TabPage page = new TabPage(text);
1950                                 page.Name = key;
1951                                 owner.InsertTab (index, page);
1952                         }
1953
1954                         public void Insert (int index, string key, string text, int imageIndex) 
1955                         {
1956                                 TabPage page = new TabPage(text);
1957                                 page.Name = key;
1958                                 owner.InsertTab (index, page);
1959                                 page.ImageIndex = imageIndex;
1960                         }
1961
1962                         public void Insert (int index, string key, string text, string imageKey) 
1963                         {
1964                                 TabPage page = new TabPage(text);
1965                                 page.Name = key;
1966                                 owner.InsertTab (index, page);
1967                                 page.ImageKey = imageKey;
1968                         }
1969 #endif
1970                         void IList.Remove (object value)
1971                         {
1972                                 TabPage page = value as TabPage;
1973                                 if (page == null)
1974                                         return;
1975                                 Remove ((TabPage) value);
1976                         }
1977                 }
1978                 #endregion      // Class TabPage.TabPageCollection
1979         }
1980 }
1981
1982