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