* TabControl.cs: Better calculation method for setting the
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TabControl.cs
blob33017073ce71346e83f73d3c6fbc687fb42eefc2
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.
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.
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
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 {
38 #region Fields
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 = 1;
48 private bool hottrack;
49 private TabPageCollection tab_pages;
50 private bool show_tool_tips;
51 private TabSizeMode size_mode;
52 private Rectangle display_rect;
53 private bool show_slider = false;
54 private ButtonState right_slider_state;
55 private ButtonState left_slider_state;
56 private int slider_pos = 0;
57 #endregion // Fields
59 #region Public Constructors
60 public TabControl ()
62 tab_pages = new TabPageCollection (this);
63 SetStyle (ControlStyles.UserPaint, false);
64 padding = ThemeEngine.Current.TabControlDefaultPadding;
65 item_size = ThemeEngine.Current.TabControlDefaultItemSize;
67 MouseDown += new MouseEventHandler (MouseDownHandler);
68 MouseUp += new MouseEventHandler (MouseUpHandler);
69 SizeChanged += new EventHandler (SizeChangedHandler);
72 #endregion // Public Constructors
74 #region Public Instance Properties
75 [DefaultValue(TabAlignment.Top)]
76 [Localizable(true)]
77 [RefreshProperties(RefreshProperties.All)]
78 public TabAlignment Alignment {
79 get { return alignment; }
80 set {
81 if (alignment == value)
82 return;
83 alignment = value;
84 if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
85 multiline = true;
86 Redraw ();
90 [DefaultValue(TabAppearance.Normal)]
91 [Localizable(true)]
92 public TabAppearance Appearance {
93 get { return appearance; }
94 set {
95 if (appearance == value)
96 return;
97 appearance = value;
98 Redraw ();
102 [Browsable(false)]
103 [EditorBrowsable(EditorBrowsableState.Never)]
104 public override Color BackColor {
105 get { return ThemeEngine.Current.ColorControl; }
106 set { /* nothing happens on set on MS */ }
109 [Browsable(false)]
110 [EditorBrowsable(EditorBrowsableState.Never)]
111 public override Image BackgroundImage {
112 get { return base.BackgroundImage; }
113 set { base.BackgroundImage = value; }
116 public override Rectangle DisplayRectangle {
117 get {
118 return ThemeEngine.Current.GetTabControlDisplayRectangle (this);
122 [DefaultValue(TabDrawMode.Normal)]
123 public TabDrawMode DrawMode {
124 get { return draw_mode; }
125 set {
126 if (draw_mode == value)
127 return;
128 draw_mode = value;
129 Redraw ();
133 [Browsable(false)]
134 [EditorBrowsable(EditorBrowsableState.Never)]
135 public override Color ForeColor {
136 get { return base.ForeColor; }
137 set { base.ForeColor = value; }
140 [DefaultValue(false)]
141 public bool HotTrack {
142 get { return hottrack; }
143 set {
144 if (hottrack == value)
145 return;
146 hottrack = value;
147 Redraw ();
151 [DefaultValue(null)]
152 public ImageList ImageList {
153 get { return image_list; }
154 set { image_list = value; }
157 [Localizable(true)]
158 public Size ItemSize {
159 get {
160 return item_size;
162 set {
163 if (value.Height < 0 || value.Width < 0)
164 throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
165 item_size = value;
166 Redraw ();
170 [DefaultValue(false)]
171 public bool Multiline {
172 get { return multiline; }
173 set {
174 if (multiline == value)
175 return;
176 multiline = value;
177 if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
178 alignment = TabAlignment.Top;
179 Redraw ();
183 [Localizable(true)]
184 public Point Padding {
185 get { return padding; }
186 set {
187 if (value.X < 0 || value.Y < 0)
188 throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
189 if (padding == value)
190 return;
191 padding = value;
192 Redraw ();
197 [Browsable(false)]
198 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
199 public int RowCount {
200 get { return row_count; }
203 [DefaultValue(-1)]
204 [Browsable(false)]
205 public int SelectedIndex {
206 get { return selected_index; }
207 set {
208 if (selected_index == value)
209 return;
210 if (selected_index < -1) {
211 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
212 "'value' must be greater than or equal to -1.");
214 if (value >= TabCount)
215 return;
217 SuspendLayout ();
219 Rectangle invalid = Rectangle.Empty;
220 bool refresh = false;
222 if (-1 != value && show_slider && value < slider_pos) {
223 slider_pos = value;
224 refresh = true;
227 if (-1 != value) {
228 int le = TabPages [value].TabBounds.Right;
229 int re = ThemeEngine.Current.GetTabControlLeftScrollRect (this).Left;
230 if (show_slider && le > re) {
231 int diff = le - re;
232 int i = 0;
234 for (i = value; i < TabPages.Count; i++) {
235 if (TabPages [i].TabBounds.Right > re)
236 break;
238 slider_pos = i;
239 refresh = true;
243 if (selected_index != -1) {
244 if (!refresh)
245 invalid = GetTabRect (selected_index);
246 Controls [selected_index].Visible = false;
248 selected_index = value;
250 OnSelectedIndexChanged (EventArgs.Empty);
252 TabPage selected = null;
254 if (selected_index != -1) {
255 selected = (TabPage) Controls [selected_index];
256 invalid = Rectangle.Union (invalid, GetTabRect (selected_index));
257 selected.Visible = true;
260 ResumeLayout ();
262 if (refresh) {
263 SizeTabs ();
264 Refresh ();
265 } else if (selected_index != -1 && selected.Row != BottomRow) {
266 DropRow (TabPages [selected_index].Row);
267 // calculating what to invalidate here seems to be slower then just
268 // refreshing the whole thing
269 SizeTabs ();
270 Refresh ();
271 } else {
272 SizeTabs ();
273 // The lines are drawn on the edges of the tabs so the invalid area should
274 // needs to include the extra pixels of line width.
275 if (appearance == TabAppearance.Normal) {
276 invalid.Inflate (6, 4);
278 Invalidate (invalid);
283 [Browsable(false)]
284 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
285 public TabPage SelectedTab {
286 get {
287 if (selected_index == -1)
288 return null;
289 return tab_pages [selected_index];
291 set {
292 int index = IndexForTabPage (value);
293 if (index == selected_index)
294 return;
295 SelectedIndex = index;
299 [DefaultValue(false)]
300 [Localizable(true)]
301 public bool ShowToolTips {
302 get { return show_tool_tips; }
303 set {
304 if (show_tool_tips == value)
305 return;
306 show_tool_tips = value;
307 Redraw ();
311 [DefaultValue(TabSizeMode.Normal)]
312 [RefreshProperties(RefreshProperties.Repaint)]
313 public TabSizeMode SizeMode {
314 get { return size_mode; }
315 set {
316 if (size_mode == value)
317 return;
318 size_mode = value;
319 Redraw ();
323 [Browsable(false)]
324 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
325 public int TabCount {
326 get {
327 return tab_pages.Count;
331 [DefaultValue(null)]
332 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
333 [MergableProperty(false)]
334 public TabPageCollection TabPages {
335 get { return tab_pages; }
338 [Browsable(false)]
339 [Bindable(false)]
340 [EditorBrowsable(EditorBrowsableState.Never)]
341 public override string Text {
342 get { return base.Text; }
343 set { base.Text = value; }
346 #endregion // Public Instance Properties
348 #region Internal Properties
349 internal bool ShowSlider {
350 get { return show_slider; }
351 set { show_slider = value; }
354 internal int SliderPos {
355 get { return slider_pos; }
358 internal ButtonState RightSliderState {
359 get { return right_slider_state; }
362 internal ButtonState LeftSliderState {
363 get { return left_slider_state; }
366 private Size DefaultItemSize {
367 get {
368 return ThemeEngine.Current.TabControlDefaultItemSize;
372 #endregion // Internal Properties
374 #region Protected Instance Properties
375 protected override CreateParams CreateParams {
376 get {
377 CreateParams c = base.CreateParams;
378 return c;
382 protected override Size DefaultSize {
383 get { return new Size (200, 100); }
386 #endregion // Protected Instance Properties
388 #region Public Instance Methods
389 public Rectangle GetTabRect (int index)
391 TabPage page = GetTab (index);
392 return page.TabBounds;
395 public Control GetControl (int index)
397 return GetTab (index);
400 public override string ToString ()
402 string res = String.Concat (base.ToString (),
403 ", TabPages.Count: ",
404 TabCount);
405 if (TabCount > 0)
406 res = String.Concat (res, ", TabPages[0]: ",
407 TabPages [0]);
408 return res;
411 #endregion // Public Instance Methods
413 #region Protected Instance Methods
414 protected override Control.ControlCollection CreateControlsInstance ()
416 return new TabControl.ControlCollection (this);
419 protected void UpdateTabSelection (bool uiselected)
421 ResizeTabPages ();
424 protected override void CreateHandle ()
426 base.CreateHandle ();
427 ResizeTabPages ();
430 protected override void OnHandleCreated (EventArgs e)
432 base.OnHandleCreated (e);
435 protected override void OnHandleDestroyed (EventArgs e)
437 base.OnHandleDestroyed (e);
440 protected virtual void OnDrawItem (DrawItemEventArgs e)
442 if (DrawItem != null && DrawMode == TabDrawMode.OwnerDrawFixed)
443 DrawItem (this, e);
446 internal void OnDrawItemInternal (DrawItemEventArgs e)
448 OnDrawItem (e);
451 protected override void OnFontChanged (EventArgs e)
453 base.OnFontChanged (e);
454 ResizeTabPages ();
457 protected override void OnResize (EventArgs e)
459 base.OnResize (e);
462 protected override void OnStyleChanged (EventArgs e)
464 base.OnStyleChanged (e);
467 protected override bool ProcessKeyPreview (ref Message m)
469 return base.ProcessKeyPreview (ref m);
472 protected override void OnKeyDown (KeyEventArgs e)
474 if (e.KeyCode == Keys.Tab && (e.KeyData & Keys.Control) != 0) {
475 if ((e.KeyData & Keys.Shift) == 0)
476 SelectedIndex = (SelectedIndex + 1) % TabCount;
477 else
478 SelectedIndex = (SelectedIndex - 1) % TabCount;
479 e.Handled = true;
480 } else if (e.KeyCode == Keys.Home) {
481 SelectedIndex = 0;
482 e.Handled = true;
483 } else if (e.KeyCode == Keys.End) {
484 SelectedIndex = TabCount - 1;
485 e.Handled = true;
486 } else if (e.KeyCode == Keys.Left && SelectedIndex > 0) {
487 SelectedIndex--;
488 e.Handled = true;
489 } else if (e.KeyCode == Keys.Right && SelectedIndex < TabCount - 1) {
490 SelectedIndex++;
491 e.Handled = true;
494 base.OnKeyDown (e);
497 protected override bool IsInputKey (Keys key)
499 switch (key & Keys.KeyCode) {
500 case Keys.Home:
501 case Keys.End:
502 case Keys.Left:
503 case Keys.Right:
504 case Keys.Tab:
505 return true;
507 return base.IsInputKey (key);
510 protected override void Dispose (bool disposing)
512 base.Dispose (disposing);
515 protected void RemoveAll ()
517 Controls.Clear ();
520 protected virtual object [] GetItems ()
522 TabPage [] pages = new TabPage [Controls.Count];
523 Controls.CopyTo (pages, 0);
524 return pages;
527 protected virtual object [] GetItems (Type type)
529 object [] pages = (object []) Array.CreateInstance (type, Controls.Count);
530 Controls.CopyTo (pages, 0);
531 return pages;
534 protected string GetToolTipText (object item)
536 TabPage page = (TabPage) item;
537 return page.ToolTipText;
540 protected override void WndProc (ref Message m)
542 base.WndProc (ref m);
545 protected virtual void OnSelectedIndexChanged (EventArgs e)
547 if (SelectedIndexChanged != null)
548 SelectedIndexChanged (this, e);
551 internal override void OnPaintInternal (PaintEventArgs pe)
553 Draw (pe.Graphics, pe.ClipRectangle);
554 pe.Handled = true;
556 #endregion // Protected Instance Methods
558 #region Internal & Private Methods
559 private bool CanScrollRight {
560 get {
561 return (slider_pos < TabCount - 1);
565 private bool CanScrollLeft {
566 get { return slider_pos > 0; }
569 private void MouseDownHandler (object sender, MouseEventArgs e)
571 if (ShowSlider) {
572 Rectangle right = ThemeEngine.Current.GetTabControlRightScrollRect (this);
573 Rectangle left = ThemeEngine.Current.GetTabControlLeftScrollRect (this);
574 if (right.Contains (e.X, e.Y)) {
575 right_slider_state = ButtonState.Pushed;
576 if (CanScrollRight) {
577 slider_pos++;
578 SizeTabs ();
580 Invalidate (new Rectangle (0, 0, Width, DisplayRectangle.Top));
581 } else {
582 Invalidate (right);
584 return;
585 } else if (left.Contains (e.X, e.Y)) {
586 left_slider_state = ButtonState.Pushed;
587 if (CanScrollLeft) {
588 slider_pos--;
589 SizeTabs ();
591 Invalidate (new Rectangle (0, 0, Width, DisplayRectangle.Top));
592 } else {
593 Invalidate (left);
595 return;
599 int count = Controls.Count;
600 for (int i = SliderPos; i < count; i++) {
601 if (!GetTabRect (i).Contains (e.X, e.Y))
602 continue;
603 SelectedIndex = i;
604 break;
608 private void MouseUpHandler (object sender, MouseEventArgs e)
610 if (ShowSlider && (left_slider_state == ButtonState.Pushed || right_slider_state == ButtonState.Pushed)) {
611 Rectangle invalid;
612 if (left_slider_state == ButtonState.Pushed)
613 invalid = ThemeEngine.Current.GetTabControlLeftScrollRect (this);
614 else
615 invalid = ThemeEngine.Current.GetTabControlRightScrollRect (this);
616 left_slider_state = ButtonState.Normal;
617 right_slider_state = ButtonState.Normal;
619 Invalidate (invalid);
623 private void SizeChangedHandler (object sender, EventArgs e)
625 Redraw ();
628 internal void UpdateTabpage (TabPage page)
633 internal int IndexForTabPage (TabPage page)
635 for (int i = 0; i < tab_pages.Count; i++) {
636 if (page == tab_pages [i])
637 return i;
639 return -1;
642 private void ResizeTabPages ()
644 CalcTabRows ();
645 SizeTabs ();
646 Rectangle r = DisplayRectangle;
647 foreach (TabPage page in Controls) {
648 page.Bounds = r;
652 private int MinimumTabWidth {
653 get {
654 return ThemeEngine.Current.TabControlMinimumTabWidth;
658 private Size TabSpacing {
659 get {
660 return ThemeEngine.Current.TabControlGetSpacing (this);
664 private void CalcTabRows ()
666 switch (Alignment) {
667 case TabAlignment.Right:
668 case TabAlignment.Left:
669 CalcTabRows (Height);
670 break;
671 default:
672 CalcTabRows (Width);
673 break;
677 private void CalcTabRows (int row_width)
679 int xpos = 4;
680 Size spacing = TabSpacing;
682 row_count = 1;
683 show_slider = false;
685 for (int i = 0; i < TabPages.Count; i++) {
686 TabPage page = TabPages [i];
687 int width;
689 page.Row = 1;
691 if (SizeMode == TabSizeMode.Fixed) {
692 width = item_size.Width;
693 } else {
694 width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
697 if (i == SelectedIndex)
698 width += 8;
699 if (width < MinimumTabWidth)
700 width = MinimumTabWidth;
702 if (xpos + width > row_width && multiline) {
703 xpos = 4;
704 for (int j = 0; j < i; j++) {
705 TabPages [j].Row++;
707 row_count++;
708 } else if (xpos + width > row_width) {
709 show_slider = true;
712 xpos += width + 1 + spacing.Width;
715 if (SelectedIndex != -1 && TabPages [SelectedIndex].Row != BottomRow)
716 DropRow (TabPages [SelectedIndex].Row);
719 private int BottomRow {
720 get {
721 switch (Alignment) {
722 case TabAlignment.Right:
723 case TabAlignment.Bottom:
724 return row_count;
725 default:
726 return 1;
731 private int Direction
733 get {
734 switch (Alignment) {
735 case TabAlignment.Right:
736 case TabAlignment.Bottom:
737 return -1;
738 default:
739 return 1;
744 private void DropRow (int row)
746 int bottom = BottomRow;
747 int direction = Direction;
749 foreach (TabPage page in TabPages) {
750 if (page.Row == row) {
751 page.Row = bottom;
752 } else if (direction == 1 && page.Row < row) {
753 page.Row += direction;
754 } else if (direction == -1 && page.Row > row) {
755 page.Row += direction;
760 private int CalcYPos ()
762 if (Alignment == TabAlignment.Bottom) {
763 Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
764 return r.Bottom + 3;
766 return 1;
769 private int CalcXPos ()
771 if (Alignment == TabAlignment.Right) {
772 Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
773 return r.Right + 4;
775 return 4;
779 private void SizeTabs ()
781 switch (Alignment) {
782 case TabAlignment.Right:
783 case TabAlignment.Left:
784 SizeTabsV (Height);
785 break;
786 default:
787 SizeTabs (Width);
788 break;
792 private void SizeTabsV (int row_width)
794 int ypos = 1;
795 int prev_row = 1;
796 Size spacing = TabSpacing;
797 int xpos = CalcXPos ();
798 int begin_prev = 0;
800 if (TabPages.Count == 0)
801 return;
803 prev_row = TabPages [0].Row;
805 for (int i = 0; i < TabPages.Count; i++) {
806 TabPage page = TabPages [i];
807 int width;
809 if (SizeMode == TabSizeMode.Fixed) {
810 width = item_size.Width;
811 } else {
812 width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
815 if (width < MinimumTabWidth)
816 width = MinimumTabWidth;
817 if (page.Row != prev_row)
818 ypos = 1;
820 page.TabBounds = new Rectangle (xpos + (row_count - page.Row) * ((item_size.Height - 2) + spacing.Width),
821 ypos, item_size.Height - 2, width);
823 if (page.Row != prev_row) {
824 if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
825 FillRowV (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Bottom) / (i - begin_prev)), spacing);
827 begin_prev = i;
830 ypos += width + spacing.Width;
831 prev_row = page.Row;
834 if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
835 FillRowV (begin_prev, TabPages.Count - 1,
836 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Bottom) / (TabPages.Count - begin_prev)), spacing);
839 if (SelectedIndex != -1) {
840 ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
844 private void SizeTabs (int row_width)
846 int ypos = CalcYPos ();
847 int prev_row = 1;
848 Size spacing = TabSpacing;
849 int xpos = 4;
850 int begin_prev = 0;
852 if (TabPages.Count == 0)
853 return;
855 prev_row = TabPages [0].Row;
857 // Reset the slider position if the slider isn't needed
858 // anymore (ie window size was increased so all tabs are visible)
859 if (!show_slider)
860 slider_pos = 0;
862 for (int i = slider_pos; i < TabPages.Count; i++) {
863 TabPage page = TabPages [i];
864 int width;
866 if (SizeMode == TabSizeMode.Fixed) {
867 width = item_size.Width;
868 } else {
869 width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
872 if (width < MinimumTabWidth)
873 width = MinimumTabWidth;
874 if (page.Row != prev_row)
875 xpos = 4;
877 page.TabBounds = new Rectangle (xpos,
878 ypos + (row_count - page.Row) * (item_size.Height + spacing.Height),
879 width, item_size.Height);
881 if (page.Row != prev_row) {
882 if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
883 FillRow (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Right) / (i - begin_prev)), spacing);
885 begin_prev = i;
888 xpos += width + 1 + spacing.Width;
889 prev_row = page.Row;
892 if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
893 FillRow (begin_prev, TabPages.Count - 1,
894 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), spacing);
897 if (SelectedIndex != -1) {
898 ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
902 private void FillRow (int start, int end, int amount, Size spacing)
904 int xpos = TabPages [start].TabBounds.Left;
905 for (int i = start; i <= end; i++) {
906 TabPage page = TabPages [i];
907 int left = xpos;
908 int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
910 page.TabBounds = new Rectangle (left, page.TabBounds.Top,
911 width, page.TabBounds.Height);
912 xpos = page.TabBounds.Right + 1 + spacing.Width;
916 private void FillRowV (int start, int end, int amount, Size spacing)
918 int ypos = TabPages [start].TabBounds.Top;
919 for (int i = start; i <= end; i++) {
920 TabPage page = TabPages [i];
921 int top = ypos;
922 int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
924 page.TabBounds = new Rectangle (page.TabBounds.Left, top,
925 page.TabBounds.Width, height);
926 ypos = page.TabBounds.Bottom + 1;
930 private void ExpandSelected (TabPage page, int left_edge, int right_edge)
932 if (Appearance != TabAppearance.Normal)
933 return;
935 if (Alignment == TabAlignment.Top || Alignment == TabAlignment.Bottom) {
936 int l = page.TabBounds.Left - 4;
937 int r = page.TabBounds.Right + 4;
938 int y = page.TabBounds.Y;
939 int h = page.TabBounds.Height + 3;
941 if (l < left_edge)
942 l = left_edge;
943 if (r > right_edge && SizeMode != TabSizeMode.Normal)
944 r = right_edge;
945 if (Alignment == TabAlignment.Top)
946 y -= 1;
947 if (Alignment == TabAlignment.Bottom)
948 y -= 2;
950 page.TabBounds = new Rectangle (l, y, r - l, h);
951 } else {
952 int l = page.TabBounds.Left - 3;
953 int r = page.TabBounds.Right + 3;
954 int t = page.TabBounds.Top - 3;
955 int b = page.TabBounds.Bottom + 3;
957 if (t < left_edge)
958 t = left_edge;
959 if (b > right_edge)
960 b = right_edge;
962 page.TabBounds = new Rectangle (l, t, r - l, b - t);
966 private void Draw (Graphics dc, Rectangle clip)
968 ThemeEngine.Current.DrawTabControl (dc, clip, this);
971 private TabPage GetTab (int index)
973 return Controls [index] as TabPage;
976 private void SetTab (int index, TabPage value)
978 ((IList) Controls).Insert (index, value);
979 Redraw ();
982 internal void Redraw ()
984 ResizeTabPages ();
985 Refresh ();
988 #endregion // Internal & Private Methods
990 #region Events
991 [Browsable(false)]
992 [EditorBrowsable(EditorBrowsableState.Never)]
993 public new event EventHandler BackColorChanged {
994 add { base.BackColorChanged += value; }
995 remove { base.BackColorChanged -= value; }
998 [Browsable(false)]
999 [EditorBrowsable(EditorBrowsableState.Never)]
1000 public new event EventHandler BackgroundImageChanged {
1001 add { base.BackgroundImageChanged += value; }
1002 remove { base.BackgroundImageChanged -= value; }
1005 [Browsable(false)]
1006 [EditorBrowsable(EditorBrowsableState.Never)]
1007 public new event EventHandler ForeColorChanged {
1008 add { base.ForeColorChanged += value; }
1009 remove { base.ForeColorChanged -= value; }
1012 [Browsable(false)]
1013 [EditorBrowsable(EditorBrowsableState.Never)]
1014 public new event PaintEventHandler Paint {
1015 add { base.Paint += value; }
1016 remove { base.Paint -= value; }
1019 [Browsable(false)]
1020 [EditorBrowsable(EditorBrowsableState.Never)]
1021 public new event EventHandler TextChanged {
1022 add { base.TextChanged += value; }
1023 remove { base.TextChanged -= value; }
1026 public event DrawItemEventHandler DrawItem;
1027 public event EventHandler SelectedIndexChanged;
1028 #endregion // Events
1031 #region Class TaControl.ControlCollection
1032 public class ControlCollection : System.Windows.Forms.Control.ControlCollection {
1034 private TabControl owner;
1035 private ArrayList list = new ArrayList ();
1037 public ControlCollection (TabControl owner) : base (owner)
1039 this.owner = owner;
1042 public override void Add (Control value)
1044 if (!(value is TabPage))
1045 throw new ArgumentException ("Cannot add " +
1046 value.GetType ().Name + " to TabControl. " +
1047 "Only TabPages can be directly added to TabControls.");
1049 value.Visible = false;
1050 base.Add (value);
1051 if (Count == 1) {
1052 owner.SelectedIndex = 0;
1053 } else {
1054 // Setting the selected index will calc the tab rows so
1055 // we don't need to do it again
1056 owner.ResizeTabPages ();
1060 public override void Remove (Control value)
1062 TabPage page = value as TabPage;
1063 if (page != null) {
1064 int index = owner.IndexForTabPage (page);
1065 if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1)
1066 owner.SelectedIndex--;
1068 base.Remove (value);
1071 #endregion // Class TabControl.ControlCollection
1073 #region Class TabPage.TabPageCollection
1074 public class TabPageCollection : IList, ICollection, IEnumerable {
1076 private TabControl owner;
1078 public TabPageCollection (TabControl owner)
1080 if (owner == null)
1081 throw new ArgumentNullException ("Value cannot be null.");
1082 this.owner = owner;
1085 [Browsable(false)]
1086 public int Count {
1087 get { return owner.Controls.Count; }
1090 public bool IsReadOnly {
1091 get { return false; }
1094 public virtual TabPage this [int index] {
1095 get {
1096 return owner.GetTab (index);
1098 set {
1099 owner.SetTab (index, value);
1103 bool ICollection.IsSynchronized {
1104 get { return false; }
1107 object ICollection.SyncRoot {
1108 get { return this; }
1111 bool IList.IsFixedSize {
1112 get { return false; }
1115 object IList.this [int index] {
1116 get {
1117 return owner.GetTab (index);
1119 set {
1120 owner.SetTab (index, (TabPage) value);
1124 public void Add (TabPage page)
1126 if (page == null)
1127 throw new ArgumentNullException ("Value cannot be null.");
1128 owner.Controls.Add (page);
1131 public void AddRange (TabPage [] pages)
1133 if (pages == null)
1134 throw new ArgumentNullException ("Value cannot be null.");
1135 owner.Controls.AddRange (pages);
1138 public virtual void Clear ()
1140 owner.Controls.Clear ();
1143 public bool Contains (TabPage page)
1145 if (page == null)
1146 throw new ArgumentNullException ("Value cannot be null.");
1147 return owner.Controls.Contains (page);
1150 public IEnumerator GetEnumerator ()
1152 return owner.Controls.GetEnumerator ();
1155 public int IndexOf (TabPage page)
1157 return owner.Controls.IndexOf (page);
1160 public void Remove (TabPage page)
1162 owner.Controls.Remove (page);
1165 public void RemoveAt (int index)
1167 owner.Controls.RemoveAt (index);
1170 void ICollection.CopyTo (Array dest, int index)
1172 owner.Controls.CopyTo (dest, index);
1175 int IList.Add (object value)
1177 TabPage page = value as TabPage;
1178 if (value == null)
1179 throw new ArgumentException ("value");
1180 owner.Controls.Add (page);
1181 return owner.Controls.IndexOf (page);
1184 bool IList.Contains (object value)
1186 TabPage page = value as TabPage;
1187 if (page == null)
1188 return false;
1189 return Contains (page);
1192 int IList.IndexOf (object value)
1194 TabPage page = value as TabPage;
1195 if (page == null)
1196 return -1;
1197 return IndexOf ((TabPage) page);
1200 void IList.Insert (int index, object value)
1202 throw new NotSupportedException ();
1205 void IList.Remove (object value)
1207 TabPage page = value as TabPage;
1208 if (page == null)
1209 return;
1210 Remove ((TabPage) value);
1213 #endregion // Class TabPage.TabPageCollection