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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2004-2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
27 using System
.Collections
;
28 using System
.ComponentModel
;
29 using System
.ComponentModel
.Design
;
33 namespace System
.Windows
.Forms
{
34 [DefaultEvent("SelectedIndexChanged")]
35 [DefaultProperty("TabPages")]
36 [Designer("System.Windows.Forms.Design.TabControlDesigner, " + Consts
.AssemblySystem_Design
, "System.ComponentModel.Design.IDesigner")]
37 public class TabControl
: Control
{
39 private int selected_index
= -1;
40 private TabAlignment alignment
;
41 private TabAppearance appearance
;
42 private TabDrawMode draw_mode
;
43 private bool multiline
;
44 private ImageList image_list
;
45 private Size item_size
= Size
.Empty
;
46 private Point padding
;
47 private int row_count
= 0;
48 private bool hottrack
;
49 private TabPageCollection tab_pages
;
50 private bool show_tool_tips
;
51 private TabSizeMode size_mode
;
52 private bool show_slider
= false;
53 private ButtonState right_slider_state
;
54 private ButtonState left_slider_state
;
55 private int slider_pos
= 0;
58 #region Public Constructors
61 tab_pages
= new TabPageCollection (this);
62 SetStyle (ControlStyles
.UserPaint
, false);
63 padding
= ThemeEngine
.Current
.TabControlDefaultPadding
;
64 item_size
= ThemeEngine
.Current
.TabControlDefaultItemSize
;
66 MouseDown
+= new MouseEventHandler (MouseDownHandler
);
67 MouseUp
+= new MouseEventHandler (MouseUpHandler
);
68 SizeChanged
+= new EventHandler (SizeChangedHandler
);
71 #endregion // Public Constructors
73 #region Public Instance Properties
74 [DefaultValue(TabAlignment
.Top
)]
76 [RefreshProperties(RefreshProperties
.All
)]
77 public TabAlignment Alignment
{
78 get { return alignment; }
80 if (alignment
== value)
83 if (alignment
== TabAlignment
.Left
|| alignment
== TabAlignment
.Right
)
89 [DefaultValue(TabAppearance
.Normal
)]
91 public TabAppearance Appearance
{
92 get { return appearance; }
94 if (appearance
== value)
102 [EditorBrowsable(EditorBrowsableState
.Never
)]
103 public override Color BackColor
{
104 get { return ThemeEngine.Current.ColorControl; }
105 set { /* nothing happens on set on MS */ }
109 [EditorBrowsable(EditorBrowsableState
.Never
)]
110 public override Image BackgroundImage
{
111 get { return base.BackgroundImage; }
112 set { base.BackgroundImage = value; }
115 public override Rectangle DisplayRectangle
{
117 return ThemeEngine
.Current
.GetTabControlDisplayRectangle (this);
121 [DefaultValue(TabDrawMode
.Normal
)]
122 public TabDrawMode DrawMode
{
123 get { return draw_mode; }
125 if (draw_mode
== value)
133 [EditorBrowsable(EditorBrowsableState
.Never
)]
134 public override Color ForeColor
{
135 get { return base.ForeColor; }
136 set { base.ForeColor = value; }
139 [DefaultValue(false)]
140 public bool HotTrack
{
141 get { return hottrack; }
143 if (hottrack
== value)
151 public ImageList ImageList
{
152 get { return image_list; }
153 set { image_list = value; }
157 public Size ItemSize
{
162 if (value.Height
< 0 || value.Width
< 0)
163 throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
169 [DefaultValue(false)]
170 public bool Multiline
{
171 get { return multiline; }
173 if (multiline
== value)
176 if (!multiline
&& alignment
== TabAlignment
.Left
|| alignment
== TabAlignment
.Right
)
177 alignment
= TabAlignment
.Top
;
183 public new Point Padding
{
184 get { return padding; }
186 if (value.X
< 0 || value.Y
< 0)
187 throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
188 if (padding
== value)
197 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
198 public int RowCount
{
199 get { return row_count; }
204 public int SelectedIndex
{
205 get { return selected_index; }
210 throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " +
211 "'SelectedIndex' must be greater than or equal to -1.");
213 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
214 "'value' must be greater than or equal to -1.");
217 if (!this.IsHandleCreated
) {
218 if (selected_index
!= value) {
219 selected_index
= value;
221 OnSelectedIndexChanged (EventArgs
.Empty
);
227 if (value >= TabCount
) {
228 if (value != selected_index
)
229 OnSelectedIndexChanged (EventArgs
.Empty
);
233 if (value == selected_index
) {
234 if (selected_index
> -1)
235 Invalidate(GetTabRect (selected_index
));
240 TabControlCancelEventArgs ret
= new TabControlCancelEventArgs (SelectedTab
, selected_index
, false, TabControlAction
.Deselecting
);
246 int old_index
= selected_index
;
247 int new_index
= value;
249 selected_index
= new_index
;
252 ret
= new TabControlCancelEventArgs (SelectedTab
, selected_index
, false, TabControlAction
.Selecting
);
255 selected_index
= old_index
;
262 Rectangle invalid
= Rectangle
.Empty
;
263 bool refresh
= false;
265 if (new_index
!= -1 && show_slider
&& new_index
< slider_pos
) {
266 slider_pos
= new_index
;
270 if (new_index
!= -1) {
271 int le
= TabPages
[new_index
].TabBounds
.Right
;
272 int re
= ThemeEngine
.Current
.GetTabControlLeftScrollRect (this).Left
;
273 if (show_slider
&& le
> re
) {
276 for (i
= new_index
; i
< TabPages
.Count
; i
++) {
277 if (TabPages
[i
].TabBounds
.Right
> re
)
285 if (old_index
!= -1 && new_index
!= -1) {
287 invalid
= GetTabRect (old_index
);
288 ((TabPage
) Controls
[old_index
]).SetVisible (false);
291 TabPage selected
= null;
293 if (new_index
!= -1) {
294 selected
= (TabPage
) Controls
[new_index
];
295 invalid
= Rectangle
.Union (invalid
, GetTabRect (new_index
));
296 selected
.SetVisible (true);
299 OnSelectedIndexChanged (EventArgs
.Empty
);
306 } else if (new_index
!= -1 && selected
.Row
!= BottomRow
) {
307 DropRow (TabPages
[new_index
].Row
);
308 // calculating what to invalidate here seems to be slower then just
309 // refreshing the whole thing
314 // The lines are drawn on the edges of the tabs so the invalid area should
315 // needs to include the extra pixels of line width.
316 if (appearance
== TabAppearance
.Normal
) {
317 invalid
.Inflate (6, 4);
319 Invalidate (invalid
);
325 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
326 public TabPage SelectedTab
{
328 if (selected_index
== -1)
330 return tab_pages
[selected_index
];
333 int index
= IndexForTabPage (value);
334 if (index
== selected_index
)
336 SelectedIndex
= index
;
340 [DefaultValue(false)]
342 public bool ShowToolTips
{
343 get { return show_tool_tips; }
345 if (show_tool_tips
== value)
347 show_tool_tips
= value;
352 [DefaultValue(TabSizeMode
.Normal
)]
353 [RefreshProperties(RefreshProperties
.Repaint
)]
354 public TabSizeMode SizeMode
{
355 get { return size_mode; }
357 if (size_mode
== value)
365 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
366 public int TabCount
{
368 return tab_pages
.Count
;
373 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
374 [MergableProperty(false)]
375 public TabPageCollection TabPages
{
376 get { return tab_pages; }
381 [EditorBrowsable(EditorBrowsableState
.Never
)]
382 public override string Text
{
383 get { return base.Text; }
384 set { base.Text = value; }
387 #endregion // Public Instance Properties
389 #region Internal Properties
390 internal bool ShowSlider
{
391 get { return show_slider; }
392 set { show_slider = value; }
395 internal int SliderPos
{
396 get { return slider_pos; }
399 internal ButtonState RightSliderState
{
400 get { return right_slider_state; }
403 internal ButtonState LeftSliderState
{
404 get { return left_slider_state; }
407 #endregion // Internal Properties
409 #region Protected Instance Properties
410 protected override CreateParams CreateParams
{
412 CreateParams c
= base.CreateParams
;
417 protected override Size DefaultSize
{
418 get { return new Size (200, 100); }
421 #endregion // Protected Instance Properties
423 #region Public Instance Methods
424 public Rectangle
GetTabRect (int index
)
426 TabPage page
= GetTab (index
);
427 return page
.TabBounds
;
430 public Control
GetControl (int index
)
432 return GetTab (index
);
436 public void SelectTab (int index
)
438 if (index
< 0 || index
> this.tab_pages
.Count
- 1)
439 throw new ArgumentOutOfRangeException ("index");
441 SelectedIndex
= index
;
445 public override string ToString ()
447 string res
= String
.Concat (base.ToString (),
448 ", TabPages.Count: ",
451 res
= String
.Concat (res
, ", TabPages[0]: ",
456 #endregion // Public Instance Methods
458 #region Protected Instance Methods
459 protected override Control
.ControlCollection
CreateControlsInstance ()
461 return new TabControl
.ControlCollection (this);
464 protected void UpdateTabSelection (bool uiselected
)
469 protected override void CreateHandle ()
471 base.CreateHandle ();
472 selected_index
= (selected_index
>= TabCount
? (TabCount
> 0 ? 0 : -1) : selected_index
);
475 if (selected_index
> -1)
476 this.SelectedTab
.SetVisible(true);
478 tab_pages
[0].SetVisible(true);
483 protected override void OnHandleCreated (EventArgs e
)
485 base.OnHandleCreated (e
);
488 protected override void OnHandleDestroyed (EventArgs e
)
490 base.OnHandleDestroyed (e
);
493 protected virtual void OnDrawItem (DrawItemEventArgs e
)
495 if (DrawMode
!= TabDrawMode
.OwnerDrawFixed
)
498 DrawItemEventHandler eh
= (DrawItemEventHandler
)(Events
[DrawItemEvent
]);
503 internal void OnDrawItemInternal (DrawItemEventArgs e
)
508 protected override void OnFontChanged (EventArgs e
)
510 base.OnFontChanged (e
);
514 protected override void OnResize (EventArgs e
)
519 protected override void OnStyleChanged (EventArgs e
)
521 base.OnStyleChanged (e
);
524 protected override bool ProcessKeyPreview (ref Message m
)
526 return base.ProcessKeyPreview (ref m
);
529 protected override void OnKeyDown (KeyEventArgs e
)
531 if (e
.KeyCode
== Keys
.Tab
&& (e
.KeyData
& Keys
.Control
) != 0) {
532 if ((e
.KeyData
& Keys
.Shift
) == 0)
533 SelectedIndex
= (SelectedIndex
+ 1) % TabCount
;
535 SelectedIndex
= (SelectedIndex
- 1) % TabCount
;
537 } else if (e
.KeyCode
== Keys
.Home
) {
540 } else if (e
.KeyCode
== Keys
.End
) {
541 SelectedIndex
= TabCount
- 1;
543 } else if (e
.KeyCode
== Keys
.Left
&& SelectedIndex
> 0) {
546 } else if (e
.KeyCode
== Keys
.Right
&& SelectedIndex
< TabCount
- 1) {
554 protected override bool IsInputKey (Keys key
)
556 switch (key
& Keys
.KeyCode
) {
563 return base.IsInputKey (key
);
566 protected override void Dispose (bool disposing
)
568 base.Dispose (disposing
);
571 protected void RemoveAll ()
576 protected virtual object [] GetItems ()
578 TabPage
[] pages
= new TabPage
[Controls
.Count
];
579 Controls
.CopyTo (pages
, 0);
583 protected virtual object [] GetItems (Type type
)
585 object [] pages
= (object []) Array
.CreateInstance (type
, Controls
.Count
);
586 Controls
.CopyTo (pages
, 0);
590 protected string GetToolTipText (object item
)
592 TabPage page
= (TabPage
) item
;
593 return page
.ToolTipText
;
596 protected override void WndProc (ref Message m
)
598 switch ((Msg
)m
.Msg
) {
599 case Msg
.WM_SETFOCUS
:
600 if (selected_index
== -1 && this.TabCount
> 0)
601 this.SelectedIndex
= 0;
602 if (selected_index
!= -1)
603 Invalidate(GetTabRect(selected_index
));
604 base.WndProc (ref m
);
606 case Msg
.WM_KILLFOCUS
:
607 if (selected_index
!= -1)
608 Invalidate(GetTabRect(selected_index
));
609 base.WndProc (ref m
);
612 base.WndProc (ref m
);
618 protected virtual void OnDeselecting (TabControlCancelEventArgs e
)
620 TabControlCancelEventHandler eh
= (TabControlCancelEventHandler
) (Events
[DeselectingEvent
]);
625 OnDeselected (new TabControlEventArgs (SelectedTab
, selected_index
, TabControlAction
.Deselected
));
628 protected virtual void OnDeselected (TabControlEventArgs e
)
630 TabControlEventHandler eh
= (TabControlEventHandler
) (Events
[DeselectedEvent
]);
634 if (this.SelectedTab
!= null)
635 this.SelectedTab
.FireLeave ();
638 protected virtual void OnSelecting (TabControlCancelEventArgs e
)
640 TabControlCancelEventHandler eh
= (TabControlCancelEventHandler
) (Events
[SelectingEvent
]);
645 OnSelected (new TabControlEventArgs (SelectedTab
, selected_index
, TabControlAction
.Selected
));
648 protected virtual void OnSelected (TabControlEventArgs e
)
650 TabControlEventHandler eh
= (TabControlEventHandler
)(Events
[SelectedEvent
]);
654 if (this.SelectedTab
!= null)
655 this.SelectedTab
.FireEnter ();
659 protected virtual void OnSelectedIndexChanged (EventArgs e
)
661 EventHandler eh
= (EventHandler
)(Events
[SelectedIndexChangedEvent
]);
666 internal override void OnPaintInternal (PaintEventArgs pe
)
668 Draw (pe
.Graphics
, pe
.ClipRectangle
);
671 #endregion // Protected Instance Methods
673 #region Internal & Private Methods
674 private bool CanScrollRight
{
676 return (slider_pos
< TabCount
- 1);
680 private bool CanScrollLeft
{
681 get { return slider_pos > 0; }
684 private void MouseDownHandler (object sender
, MouseEventArgs e
)
687 Rectangle right
= ThemeEngine
.Current
.GetTabControlRightScrollRect (this);
688 Rectangle left
= ThemeEngine
.Current
.GetTabControlLeftScrollRect (this);
689 if (right
.Contains (e
.X
, e
.Y
)) {
690 right_slider_state
= ButtonState
.Pushed
;
691 if (CanScrollRight
) {
695 Invalidate (new Rectangle (0, 0, Width
, DisplayRectangle
.Top
));
700 } else if (left
.Contains (e
.X
, e
.Y
)) {
701 left_slider_state
= ButtonState
.Pushed
;
706 Invalidate (new Rectangle (0, 0, Width
, DisplayRectangle
.Top
));
714 int count
= Controls
.Count
;
715 for (int i
= SliderPos
; i
< count
; i
++) {
716 if (!GetTabRect (i
).Contains (e
.X
, e
.Y
))
723 private void MouseUpHandler (object sender
, MouseEventArgs e
)
725 if (ShowSlider
&& (left_slider_state
== ButtonState
.Pushed
|| right_slider_state
== ButtonState
.Pushed
)) {
727 if (left_slider_state
== ButtonState
.Pushed
)
728 invalid
= ThemeEngine
.Current
.GetTabControlLeftScrollRect (this);
730 invalid
= ThemeEngine
.Current
.GetTabControlRightScrollRect (this);
731 left_slider_state
= ButtonState
.Normal
;
732 right_slider_state
= ButtonState
.Normal
;
734 Invalidate (invalid
);
738 private void SizeChangedHandler (object sender
, EventArgs e
)
743 internal void UpdateTabpage (TabPage page
)
748 internal int IndexForTabPage (TabPage page
)
750 for (int i
= 0; i
< tab_pages
.Count
; i
++) {
751 if (page
== tab_pages
[i
])
757 private void ResizeTabPages ()
761 Rectangle r
= DisplayRectangle
;
762 foreach (TabPage page
in Controls
) {
767 private int MinimumTabWidth
{
769 return ThemeEngine
.Current
.TabControlMinimumTabWidth
;
773 private Size TabSpacing
{
775 return ThemeEngine
.Current
.TabControlGetSpacing (this);
779 private void CalcTabRows ()
782 case TabAlignment
.Right
:
783 case TabAlignment
.Left
:
784 CalcTabRows (Height
);
792 private void CalcTabRows (int row_width
)
795 Size spacing
= TabSpacing
;
797 if (TabPages
.Count
> 0)
801 for (int i
= 0; i
< TabPages
.Count
; i
++) {
802 TabPage page
= TabPages
[i
];
807 if (SizeMode
== TabSizeMode
.Fixed
) {
808 width
= item_size
.Width
;
810 width
= (int) DeviceContext
.MeasureString (page
.Text
, Font
).Width
+ (Padding
.X
* 2);
811 if (ImageList
!= null && page
.ImageIndex
>= 0 && page
.ImageIndex
< ImageList
.Images
.Count
) {
812 width
+= ImageList
.ImageSize
.Width
+ 2;
813 item_size
.Height
= ImageList
.ImageSize
.Height
+ 3;
817 if (i
== SelectedIndex
)
819 if (width
< MinimumTabWidth
)
820 width
= MinimumTabWidth
;
822 if (xpos
+ width
> row_width
&& multiline
) {
824 for (int j
= 0; j
< i
; j
++) {
828 } else if (xpos
+ width
> row_width
) {
832 xpos
+= width
+ 1 + spacing
.Width
;
835 if (SelectedIndex
!= -1 && TabPages
[SelectedIndex
].Row
!= BottomRow
)
836 DropRow (TabPages
[SelectedIndex
].Row
);
839 private int BottomRow
{
842 case TabAlignment
.Right
:
843 case TabAlignment
.Bottom
:
851 private int Direction
855 case TabAlignment
.Right
:
856 case TabAlignment
.Bottom
:
864 private void DropRow (int row
)
866 int bottom
= BottomRow
;
867 int direction
= Direction
;
869 foreach (TabPage page
in TabPages
) {
870 if (page
.Row
== row
) {
872 } else if (direction
== 1 && page
.Row
< row
) {
873 page
.Row
+= direction
;
874 } else if (direction
== -1 && page
.Row
> row
) {
875 page
.Row
+= direction
;
880 private int CalcYPos ()
882 if (Alignment
== TabAlignment
.Bottom
) {
883 Rectangle r
= ThemeEngine
.Current
.GetTabControlDisplayRectangle (this);
889 private int CalcXPos ()
891 if (Alignment
== TabAlignment
.Right
) {
892 Rectangle r
= ThemeEngine
.Current
.GetTabControlDisplayRectangle (this);
899 private void SizeTabs ()
902 case TabAlignment
.Right
:
903 case TabAlignment
.Left
:
912 private void SizeTabsV (int row_width
)
916 Size spacing
= TabSpacing
;
917 int xpos
= CalcXPos ();
920 if (TabPages
.Count
== 0)
923 prev_row
= TabPages
[0].Row
;
925 for (int i
= 0; i
< TabPages
.Count
; i
++) {
926 TabPage page
= TabPages
[i
];
929 if (SizeMode
== TabSizeMode
.Fixed
) {
930 width
= item_size
.Width
;
932 width
= (int) DeviceContext
.MeasureString (page
.Text
, Font
).Width
+ (Padding
.X
* 2);
933 if (ImageList
!= null && page
.ImageIndex
>= 0 && page
.ImageIndex
< ImageList
.Images
.Count
) {
934 width
+= ImageList
.ImageSize
.Width
+ 2;
935 item_size
.Height
= ImageList
.ImageSize
.Height
+ 3;
939 if (width
< MinimumTabWidth
)
940 width
= MinimumTabWidth
;
941 if (page
.Row
!= prev_row
)
944 page
.TabBounds
= new Rectangle (xpos
+ (row_count
- page
.Row
) * ((item_size
.Height
- 2) + spacing
.Width
),
945 ypos
, item_size
.Height
- 2, width
);
947 if (page
.Row
!= prev_row
) {
948 if (SizeMode
== TabSizeMode
.FillToRight
&& !ShowSlider
) {
949 FillRowV (begin_prev
, i
- 1, ((row_width
- TabPages
[i
- 1].TabBounds
.Bottom
) / (i
- begin_prev
)), spacing
);
954 ypos
+= width
+ spacing
.Width
;
958 if (SizeMode
== TabSizeMode
.FillToRight
&& !ShowSlider
) {
959 FillRowV (begin_prev
, TabPages
.Count
- 1,
960 ((row_width
- TabPages
[TabPages
.Count
- 1].TabBounds
.Bottom
) / (TabPages
.Count
- begin_prev
)), spacing
);
963 if (SelectedIndex
!= -1) {
964 ExpandSelected (TabPages
[SelectedIndex
], 2, row_width
- 1);
968 private void SizeTabs (int row_width
)
970 int ypos
= CalcYPos ();
972 Size spacing
= TabSpacing
;
976 if (TabPages
.Count
== 0)
979 prev_row
= TabPages
[0].Row
;
981 // Reset the slider position if the slider isn't needed
982 // anymore (ie window size was increased so all tabs are visible)
986 for (int i
= slider_pos
; i
< TabPages
.Count
; i
++) {
987 TabPage page
= TabPages
[i
];
990 if (SizeMode
== TabSizeMode
.Fixed
) {
991 width
= item_size
.Width
;
993 width
= (int) DeviceContext
.MeasureString (page
.Text
, Font
).Width
+ (Padding
.X
* 2);
994 if (ImageList
!= null && page
.ImageIndex
>= 0 && page
.ImageIndex
< ImageList
.Images
.Count
) {
995 width
+= ImageList
.ImageSize
.Width
+ 2;
996 item_size
.Height
= ImageList
.ImageSize
.Height
+ 3;
1000 if (width
< MinimumTabWidth
)
1001 width
= MinimumTabWidth
;
1002 if (page
.Row
!= prev_row
)
1005 page
.TabBounds
= new Rectangle (xpos
,
1006 ypos
+ (row_count
- page
.Row
) * (item_size
.Height
+ spacing
.Height
),
1007 width
, item_size
.Height
);
1009 if (page
.Row
!= prev_row
) {
1010 if (SizeMode
== TabSizeMode
.FillToRight
&& !ShowSlider
) {
1011 FillRow (begin_prev
, i
- 1, ((row_width
- TabPages
[i
- 1].TabBounds
.Right
) / (i
- begin_prev
)), spacing
);
1016 xpos
+= width
+ 1 + spacing
.Width
;
1017 prev_row
= page
.Row
;
1020 if (SizeMode
== TabSizeMode
.FillToRight
&& !ShowSlider
) {
1021 FillRow (begin_prev
, TabPages
.Count
- 1,
1022 ((row_width
- TabPages
[TabPages
.Count
- 1].TabBounds
.Right
) / (TabPages
.Count
- begin_prev
)), spacing
);
1025 if (SelectedIndex
!= -1) {
1026 ExpandSelected (TabPages
[SelectedIndex
], 2, row_width
- 1);
1030 private void FillRow (int start
, int end
, int amount
, Size spacing
)
1032 int xpos
= TabPages
[start
].TabBounds
.Left
;
1033 for (int i
= start
; i
<= end
; i
++) {
1034 TabPage page
= TabPages
[i
];
1036 int width
= (i
== end
? Width
- left
- 3 : page
.TabBounds
.Width
+ amount
);
1038 page
.TabBounds
= new Rectangle (left
, page
.TabBounds
.Top
,
1039 width
, page
.TabBounds
.Height
);
1040 xpos
= page
.TabBounds
.Right
+ 1 + spacing
.Width
;
1044 private void FillRowV (int start
, int end
, int amount
, Size spacing
)
1046 int ypos
= TabPages
[start
].TabBounds
.Top
;
1047 for (int i
= start
; i
<= end
; i
++) {
1048 TabPage page
= TabPages
[i
];
1050 int height
= (i
== end
? Height
- top
- 5 : page
.TabBounds
.Height
+ amount
);
1052 page
.TabBounds
= new Rectangle (page
.TabBounds
.Left
, top
,
1053 page
.TabBounds
.Width
, height
);
1054 ypos
= page
.TabBounds
.Bottom
+ 1;
1058 private void ExpandSelected (TabPage page
, int left_edge
, int right_edge
)
1060 if (Appearance
!= TabAppearance
.Normal
)
1063 if (Alignment
== TabAlignment
.Top
|| Alignment
== TabAlignment
.Bottom
) {
1064 int l
= page
.TabBounds
.Left
- 4;
1065 int r
= page
.TabBounds
.Right
+ 4;
1066 int y
= page
.TabBounds
.Y
;
1067 int h
= page
.TabBounds
.Height
+ 3;
1071 if (r
> right_edge
&& SizeMode
!= TabSizeMode
.Normal
)
1073 if (Alignment
== TabAlignment
.Top
)
1075 if (Alignment
== TabAlignment
.Bottom
)
1078 page
.TabBounds
= new Rectangle (l
, y
, r
- l
, h
);
1080 int l
= page
.TabBounds
.Left
- 3;
1081 int r
= page
.TabBounds
.Right
+ 3;
1082 int t
= page
.TabBounds
.Top
- 3;
1083 int b
= page
.TabBounds
.Bottom
+ 3;
1090 page
.TabBounds
= new Rectangle (l
, t
, r
- l
, b
- t
);
1094 private void Draw (Graphics dc
, Rectangle clip
)
1096 ThemeEngine
.Current
.DrawTabControl (dc
, clip
, this);
1099 private TabPage
GetTab (int index
)
1101 return Controls
[index
] as TabPage
;
1104 private void SetTab (int index
, TabPage
value)
1106 ((IList
) Controls
).Insert (index
, value);
1110 internal void Redraw ()
1112 if (!IsHandleCreated
)
1119 #endregion // Internal & Private Methods
1123 [EditorBrowsable(EditorBrowsableState
.Never
)]
1124 public new event EventHandler BackColorChanged
{
1125 add { base.BackColorChanged += value; }
1126 remove { base.BackColorChanged -= value; }
1130 [EditorBrowsable(EditorBrowsableState
.Never
)]
1131 public new event EventHandler BackgroundImageChanged
{
1132 add { base.BackgroundImageChanged += value; }
1133 remove { base.BackgroundImageChanged -= value; }
1137 [EditorBrowsable(EditorBrowsableState
.Never
)]
1138 public new event EventHandler ForeColorChanged
{
1139 add { base.ForeColorChanged += value; }
1140 remove { base.ForeColorChanged -= value; }
1144 [EditorBrowsable(EditorBrowsableState
.Never
)]
1145 public new event PaintEventHandler Paint
{
1146 add { base.Paint += value; }
1147 remove { base.Paint -= value; }
1151 [EditorBrowsable(EditorBrowsableState
.Never
)]
1152 public new event EventHandler TextChanged
{
1153 add { base.TextChanged += value; }
1154 remove { base.TextChanged -= value; }
1157 static object DrawItemEvent
= new object ();
1158 static object SelectedIndexChangedEvent
= new object ();
1160 public event DrawItemEventHandler DrawItem
{
1161 add { Events.AddHandler (DrawItemEvent, value); }
1162 remove { Events.RemoveHandler (DrawItemEvent, value); }
1165 public event EventHandler SelectedIndexChanged
{
1166 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
1167 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
1171 static object SelectedEvent
= new object ();
1173 public event TabControlEventHandler Selected
{
1174 add { Events.AddHandler (SelectedEvent, value); }
1175 remove { Events.RemoveHandler (SelectedEvent, value); }
1178 static object DeselectedEvent
= new object ();
1180 public event TabControlEventHandler Deselected
1182 add { Events.AddHandler (DeselectedEvent, value); }
1183 remove { Events.RemoveHandler (DeselectedEvent, value); }
1186 static object SelectingEvent
= new object ();
1188 public event TabControlCancelEventHandler Selecting
1190 add { Events.AddHandler (SelectingEvent, value); }
1191 remove { Events.RemoveHandler (SelectingEvent, value); }
1194 static object DeselectingEvent
= new object ();
1196 public event TabControlCancelEventHandler Deselecting
1198 add { Events.AddHandler (DeselectingEvent, value); }
1199 remove { Events.RemoveHandler (DeselectingEvent, value); }
1202 #endregion // Events
1205 #region Class TaControl.ControlCollection
1206 public new class ControlCollection
: System
.Windows
.Forms
.Control
.ControlCollection
{
1208 private TabControl owner
;
1210 public ControlCollection (TabControl owner
) : base (owner
)
1215 public override void Add (Control
value)
1217 TabPage page
= value as TabPage
;
1219 throw new ArgumentException ("Cannot add " +
1220 value.GetType ().Name
+ " to TabControl. " +
1221 "Only TabPages can be directly added to TabControls.");
1223 page
.SetVisible (false);
1225 if (owner
.TabCount
== 1 && owner
.selected_index
< 0)
1226 owner
.SelectedIndex
= 0;
1230 public override void Remove (Control
value)
1232 TabPage page
= value as TabPage
;
1234 int index
= owner
.IndexForTabPage (page
);
1235 if (index
< owner
.SelectedIndex
|| owner
.SelectedIndex
== Count
- 1)
1236 owner
.SelectedIndex
--;
1238 base.Remove (value);
1241 #endregion // Class TabControl.ControlCollection
1243 #region Class TabPage.TabPageCollection
1244 public class TabPageCollection
: IList
, ICollection
, IEnumerable
{
1246 private TabControl owner
;
1248 public TabPageCollection (TabControl owner
)
1251 throw new ArgumentNullException ("Value cannot be null.");
1257 get { return owner.Controls.Count; }
1260 public bool IsReadOnly
{
1261 get { return false; }
1264 public virtual TabPage
this [int index
] {
1266 return owner
.GetTab (index
);
1269 owner
.SetTab (index
, value);
1273 bool ICollection
.IsSynchronized
{
1274 get { return false; }
1277 object ICollection
.SyncRoot
{
1278 get { return this; }
1281 bool IList
.IsFixedSize
{
1282 get { return false; }
1285 object IList
.this [int index
] {
1287 return owner
.GetTab (index
);
1290 owner
.SetTab (index
, (TabPage
) value);
1294 public void Add (TabPage page
)
1297 throw new ArgumentNullException ("Value cannot be null.");
1298 owner
.Controls
.Add (page
);
1301 public void AddRange (TabPage
[] pages
)
1304 throw new ArgumentNullException ("Value cannot be null.");
1305 owner
.Controls
.AddRange (pages
);
1308 public virtual void Clear ()
1310 owner
.Controls
.Clear ();
1313 public bool Contains (TabPage page
)
1316 throw new ArgumentNullException ("Value cannot be null.");
1317 return owner
.Controls
.Contains (page
);
1320 public IEnumerator
GetEnumerator ()
1322 return owner
.Controls
.GetEnumerator ();
1325 public int IndexOf (TabPage page
)
1327 return owner
.Controls
.IndexOf (page
);
1330 public void Remove (TabPage page
)
1332 owner
.Controls
.Remove (page
);
1335 public void RemoveAt (int index
)
1337 owner
.Controls
.RemoveAt (index
);
1340 void ICollection
.CopyTo (Array dest
, int index
)
1342 owner
.Controls
.CopyTo (dest
, index
);
1345 int IList
.Add (object value)
1347 TabPage page
= value as TabPage
;
1349 throw new ArgumentException ("value");
1350 owner
.Controls
.Add (page
);
1351 return owner
.Controls
.IndexOf (page
);
1354 bool IList
.Contains (object value)
1356 TabPage page
= value as TabPage
;
1359 return Contains (page
);
1362 int IList
.IndexOf (object value)
1364 TabPage page
= value as TabPage
;
1367 return IndexOf ((TabPage
) page
);
1370 void IList
.Insert (int index
, object value)
1372 throw new NotSupportedException ();
1375 void IList
.Remove (object value)
1377 TabPage page
= value as TabPage
;
1380 Remove ((TabPage
) value);
1383 #endregion // Class TabPage.TabPageCollection