Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/TabControl.cs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/TabControl.cs1224
1 files changed, 1224 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TabControl.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TabControl.cs
new file mode 100644
index 00000000000..de6c042cc49
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TabControl.cs
@@ -0,0 +1,1224 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper (jackson@ximian.com)
+
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Drawing;
+
+
+namespace System.Windows.Forms {
+ [DefaultEvent("SelectedIndexChanged")]
+ [DefaultProperty("TabPages")]
+ [Designer("System.Windows.Forms.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+ public class TabControl : Control {
+ #region Fields
+ private int selected_index = -1;
+ private TabAlignment alignment;
+ private TabAppearance appearance;
+ private TabDrawMode draw_mode;
+ private bool multiline;
+ private ImageList image_list;
+ private Size item_size = Size.Empty;
+ private Point padding;
+ private int row_count = 1;
+ private bool hottrack;
+ private TabPageCollection tab_pages;
+ private bool show_tool_tips;
+ private TabSizeMode size_mode;
+ private Rectangle display_rect;
+ private bool show_slider = false;
+ private ButtonState right_slider_state;
+ private ButtonState left_slider_state;
+ private int slider_pos = 0;
+ #endregion // Fields
+
+ #region Public Constructors
+ public TabControl ()
+ {
+ tab_pages = new TabPageCollection (this);
+ SetStyle (ControlStyles.UserPaint, false);
+ padding = ThemeEngine.Current.TabControlDefaultPadding;
+ item_size = ThemeEngine.Current.TabControlDefaultItemSize;
+
+ MouseDown += new MouseEventHandler (MouseDownHandler);
+ MouseUp += new MouseEventHandler (MouseUpHandler);
+ SizeChanged += new EventHandler (SizeChangedHandler);
+ }
+
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ [DefaultValue(TabAlignment.Top)]
+ [Localizable(true)]
+ [RefreshProperties(RefreshProperties.All)]
+ public TabAlignment Alignment {
+ get { return alignment; }
+ set {
+ if (alignment == value)
+ return;
+ alignment = value;
+ if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
+ multiline = true;
+ Redraw ();
+ }
+ }
+
+ [DefaultValue(TabAppearance.Normal)]
+ [Localizable(true)]
+ public TabAppearance Appearance {
+ get { return appearance; }
+ set {
+ if (appearance == value)
+ return;
+ appearance = value;
+ Redraw ();
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Color BackColor {
+ get { return base.BackColor; }
+ set { /* nothing happens on set on MS */ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Image BackgroundImage {
+ get { return base.BackgroundImage; }
+ set { base.BackgroundImage = value; }
+ }
+
+ public override Rectangle DisplayRectangle {
+ get {
+ return ThemeEngine.Current.GetTabControlDisplayRectangle (this);
+ }
+ }
+
+ [DefaultValue(TabDrawMode.Normal)]
+ public TabDrawMode DrawMode {
+ get { return draw_mode; }
+ set {
+ if (draw_mode == value)
+ return;
+ draw_mode = value;
+ Redraw ();
+ }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Color ForeColor {
+ get { return base.ForeColor; }
+ set { base.ForeColor = value; }
+ }
+
+ [DefaultValue(false)]
+ public bool HotTrack {
+ get { return hottrack; }
+ set {
+ if (hottrack == value)
+ return;
+ hottrack = value;
+ Redraw ();
+ }
+ }
+
+ [DefaultValue(null)]
+ public ImageList ImageList {
+ get { return image_list; }
+ set { image_list = value; }
+ }
+
+ [Localizable(true)]
+ public Size ItemSize {
+ get {
+ return item_size;
+ }
+ set {
+ if (value.Height < 0 || value.Width < 0)
+ throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
+ item_size = value;
+ Redraw ();
+ }
+ }
+
+ [DefaultValue(false)]
+ public bool Multiline {
+ get { return multiline; }
+ set {
+ if (multiline == value)
+ return;
+ multiline = value;
+ if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
+ alignment = TabAlignment.Top;
+ Redraw ();
+ }
+ }
+
+ [Localizable(true)]
+ public Point Padding {
+ get { return padding; }
+ set {
+ if (value.X < 0 || value.Y < 0)
+ throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
+ if (padding == value)
+ return;
+ padding = value;
+ Redraw ();
+ }
+
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public int RowCount {
+ get { return row_count; }
+ }
+
+ [DefaultValue(-1)]
+ [Browsable(false)]
+ public int SelectedIndex {
+ get { return selected_index; }
+ set {
+ if (selected_index == value)
+ return;
+ if (selected_index < -1) {
+ throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
+ "'value' must be greater than or equal to -1.");
+ }
+
+ SuspendLayout ();
+
+ Rectangle invalid = Rectangle.Empty;
+ bool refresh = false;
+
+ if (-1 != value && show_slider && value < slider_pos) {
+ slider_pos = value;
+ refresh = true;
+ }
+
+ int le = TabPages [value].TabBounds.Right;
+ int re = ThemeEngine.Current.GetTabControlLeftScrollRect (this).Left;
+
+ if (-1 != value && show_slider && le > re) {
+ int diff = le - re;
+ int ind = value - 1;
+ while (ind > 0 && diff > 0) {
+ diff -= TabPages [ind++].Width;
+ }
+ slider_pos = ind - 1;
+ refresh = true;
+ }
+
+ if (selected_index != -1) {
+ if (!refresh)
+ invalid = GetTabRect (selected_index);
+ Controls [selected_index].Visible = false;
+ }
+ selected_index = value;
+
+ OnSelectedIndexChanged (EventArgs.Empty);
+
+ TabPage selected = (TabPage) Controls [selected_index];
+
+ if (selected_index != -1) {
+ invalid = Rectangle.Union (invalid, GetTabRect (selected_index));
+ selected.Visible = true;
+ }
+
+ ResumeLayout ();
+
+ if (refresh) {
+ SizeTabs ();
+ Refresh ();
+ } else if (selected_index != -1 && selected.Row != BottomRow) {
+ DropRow (TabPages [selected_index].Row);
+ // calculating what to invalidate here seems to be slower then just
+ // refreshing the whole thing
+ SizeTabs ();
+ Refresh ();
+ } else {
+ SizeTabs ();
+ // The lines are drawn on the edges of the tabs so the invalid area should
+ // needs to include the extra pixels of line width.
+ if (appearance == TabAppearance.Normal) {
+ invalid.Inflate (6, 4);
+ }
+ Invalidate (invalid);
+ }
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public TabPage SelectedTab {
+ get {
+ if (selected_index == -1)
+ return null;
+ return tab_pages [selected_index];
+ }
+ set {
+ int index = IndexForTabPage (value);
+ if (index == selected_index)
+ return;
+ SelectedIndex = index;
+ }
+ }
+
+ [DefaultValue(false)]
+ [Localizable(true)]
+ public bool ShowToolTips {
+ get { return show_tool_tips; }
+ set {
+ if (show_tool_tips == value)
+ return;
+ show_tool_tips = value;
+ Redraw ();
+ }
+ }
+
+ [DefaultValue(TabSizeMode.Normal)]
+ [RefreshProperties(RefreshProperties.Repaint)]
+ public TabSizeMode SizeMode {
+ get { return size_mode; }
+ set {
+ if (size_mode == value)
+ return;
+ size_mode = value;
+ Redraw ();
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public int TabCount {
+ get {
+ return tab_pages.Count;
+ }
+ }
+
+ [DefaultValue(null)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [MergableProperty(false)]
+ public TabPageCollection TabPages {
+ get { return tab_pages; }
+ }
+
+ [Browsable(false)]
+ [Bindable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string Text {
+ get { return base.Text; }
+ set { base.Text = value; }
+ }
+
+ #endregion // Public Instance Properties
+
+ #region Internal Properties
+ internal bool ShowSlider {
+ get { return show_slider; }
+ set { show_slider = value; }
+ }
+
+ internal int SliderPos {
+ get { return slider_pos; }
+ }
+
+ internal ButtonState RightSliderState {
+ get { return right_slider_state; }
+ }
+
+ internal ButtonState LeftSliderState {
+ get { return left_slider_state; }
+ }
+
+ private Size DefaultItemSize {
+ get {
+ return ThemeEngine.Current.TabControlDefaultItemSize;
+ }
+ }
+
+ #endregion // Internal Properties
+
+ #region Protected Instance Properties
+ protected override CreateParams CreateParams {
+ get {
+ CreateParams c = base.CreateParams;
+ return c;
+ }
+ }
+
+ protected override Size DefaultSize {
+ get { return new Size (200, 100); }
+ }
+
+ #endregion // Protected Instance Properties
+
+ #region Public Instance Methods
+ public Rectangle GetTabRect (int index)
+ {
+ TabPage page = GetTab (index);
+ return page.TabBounds;
+ }
+
+ public Control GetControl (int index)
+ {
+ return GetTab (index);
+ }
+
+ public override string ToString ()
+ {
+ string res = String.Concat (base.ToString (),
+ ", TabPages.Count: ",
+ TabCount);
+ if (TabCount > 0)
+ res = String.Concat (res, ", TabPages[0]: ",
+ TabPages [0]);
+ return res;
+ }
+
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ protected override Control.ControlCollection CreateControlsInstance ()
+ {
+ return new TabControl.ControlCollection (this);
+ }
+
+ protected void UpdateTabSelection (bool uiselected)
+ {
+ ResizeTabPages ();
+ }
+
+ protected override void CreateHandle ()
+ {
+ base.CreateHandle ();
+ ResizeTabPages ();
+ }
+
+ protected override void OnHandleCreated (EventArgs e)
+ {
+ base.OnHandleCreated (e);
+ }
+
+ protected override void OnHandleDestroyed (EventArgs e)
+ {
+ base.OnHandleDestroyed (e);
+ }
+
+ protected virtual void OnDrawItem (DrawItemEventArgs e)
+ {
+ if (DrawItem != null && DrawMode == TabDrawMode.OwnerDrawFixed)
+ DrawItem (this, e);
+ }
+
+ internal void OnDrawItemInternal (DrawItemEventArgs e)
+ {
+ OnDrawItem (e);
+ }
+
+ protected override void OnFontChanged (EventArgs e)
+ {
+ base.OnFontChanged (e);
+ ResizeTabPages ();
+ }
+
+ protected override void OnResize (EventArgs e)
+ {
+ base.OnResize (e);
+ }
+
+ protected override void OnStyleChanged (EventArgs e)
+ {
+ base.OnStyleChanged (e);
+ }
+
+ protected override bool ProcessKeyPreview (ref Message m)
+ {
+ return base.ProcessKeyPreview (ref m);
+ }
+
+ protected override void OnKeyDown (KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Tab && (e.KeyData & Keys.Control) != 0) {
+ if ((e.KeyData & Keys.Shift) == 0)
+ SelectedIndex = (SelectedIndex + 1) % TabCount;
+ else
+ SelectedIndex = (SelectedIndex - 1) % TabCount;
+ e.Handled = true;
+ } else if (e.KeyCode == Keys.Home) {
+ SelectedIndex = 0;
+ e.Handled = true;
+ } else if (e.KeyCode == Keys.End) {
+ SelectedIndex = TabCount - 1;
+ e.Handled = true;
+ } else if (e.KeyCode == Keys.Left && SelectedIndex > 0) {
+ SelectedIndex--;
+ e.Handled = true;
+ } else if (e.KeyCode == Keys.Right && SelectedIndex < TabCount - 1) {
+ SelectedIndex++;
+ e.Handled = true;
+ }
+
+ base.OnKeyDown (e);
+ }
+
+ protected override bool IsInputKey (Keys key)
+ {
+ switch (key & Keys.KeyCode) {
+ case Keys.Home:
+ case Keys.End:
+ case Keys.Left:
+ case Keys.Right:
+ case Keys.Tab:
+ return true;
+ }
+ return base.IsInputKey (key);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ }
+
+ protected void RemoveAll ()
+ {
+ Controls.Clear ();
+ }
+
+ protected virtual object [] GetItems ()
+ {
+ TabPage [] pages = new TabPage [Controls.Count];
+ Controls.CopyTo (pages, 0);
+ return pages;
+ }
+
+ protected virtual object [] GetItems (Type type)
+ {
+ object [] pages = (object []) Array.CreateInstance (type, Controls.Count);
+ Controls.CopyTo (pages, 0);
+ return pages;
+ }
+
+ protected string GetToolTipText (object item)
+ {
+ TabPage page = (TabPage) item;
+ return page.ToolTipText;
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ switch ((Msg) m.Msg) {
+ case Msg.WM_PAINT:
+ PaintEventArgs paint_event;
+ paint_event = XplatUI.PaintEventStart (Handle, true);
+ PaintInternal (paint_event);
+ XplatUI.PaintEventEnd (Handle, true);
+ break;
+ default:
+ base.WndProc (ref m);
+ break;
+ }
+ }
+
+ protected virtual void OnSelectedIndexChanged (EventArgs e)
+ {
+ if (SelectedIndexChanged != null)
+ SelectedIndexChanged (this, e);
+ }
+
+ #endregion // Protected Instance Methods
+
+ #region Internal & Private Methods
+ private bool CanScrollRight {
+ get {
+ return (slider_pos < TabCount - 1);
+ }
+ }
+
+ private bool CanScrollLeft {
+ get { return slider_pos > 0; }
+ }
+
+ private void MouseDownHandler (object sender, MouseEventArgs e)
+ {
+ if (ShowSlider) {
+ Rectangle right = ThemeEngine.Current.GetTabControlRightScrollRect (this);
+ Rectangle left = ThemeEngine.Current.GetTabControlLeftScrollRect (this);
+ if (right.Contains (e.X, e.Y)) {
+ right_slider_state = ButtonState.Pushed;
+ if (CanScrollRight) {
+ slider_pos++;
+ SizeTabs ();
+
+ Invalidate (new Rectangle (0, 0, Width, DisplayRectangle.Top));
+ } else {
+ Invalidate (right);
+ }
+ return;
+ } else if (left.Contains (e.X, e.Y)) {
+ left_slider_state = ButtonState.Pushed;
+ if (CanScrollLeft) {
+ slider_pos--;
+ SizeTabs ();
+
+ Invalidate (new Rectangle (0, 0, Width, DisplayRectangle.Top));
+ } else {
+ Invalidate (left);
+ }
+ return;
+ }
+ }
+
+ int count = Controls.Count;
+ for (int i = SliderPos; i < count; i++) {
+ if (!GetTabRect (i).Contains (e.X, e.Y))
+ continue;
+ SelectedIndex = i;
+ break;
+ }
+ }
+
+ private void MouseUpHandler (object sender, MouseEventArgs e)
+ {
+ if (ShowSlider && (left_slider_state == ButtonState.Pushed || right_slider_state == ButtonState.Pushed)) {
+ Rectangle invalid;
+ if (left_slider_state == ButtonState.Pushed)
+ invalid = ThemeEngine.Current.GetTabControlLeftScrollRect (this);
+ else
+ invalid = ThemeEngine.Current.GetTabControlRightScrollRect (this);
+ left_slider_state = ButtonState.Normal;
+ right_slider_state = ButtonState.Normal;
+
+ Invalidate (invalid);
+ }
+ }
+
+ private void SizeChangedHandler (object sender, EventArgs e)
+ {
+ Redraw ();
+ }
+
+ internal void UpdateTabpage (TabPage page)
+ {
+
+ }
+
+ internal int IndexForTabPage (TabPage page)
+ {
+ for (int i = 0; i < tab_pages.Count; i++) {
+ if (page == tab_pages [i])
+ return i;
+ }
+ return -1;
+ }
+
+ private void ResizeTabPages ()
+ {
+ CalcTabRows ();
+ SizeTabs ();
+ Rectangle r = DisplayRectangle;
+ foreach (TabPage page in Controls) {
+ page.Bounds = r;
+ }
+ }
+
+ private int MinimumTabWidth {
+ get {
+ return ThemeEngine.Current.TabControlMinimumTabWidth;
+ }
+ }
+
+ private Size TabSpacing {
+ get {
+ return ThemeEngine.Current.TabControlGetSpacing (this);
+ }
+ }
+
+ private void CalcTabRows ()
+ {
+ switch (Alignment) {
+ case TabAlignment.Right:
+ case TabAlignment.Left:
+ CalcTabRows (Height);
+ break;
+ default:
+ CalcTabRows (Width);
+ break;
+ }
+ }
+
+ private void CalcTabRows (int row_width)
+ {
+ int xpos = 4;
+ Size spacing = TabSpacing;
+
+ row_count = 1;
+ show_slider = false;
+
+ for (int i = 0; i < TabPages.Count; i++) {
+ TabPage page = TabPages [i];
+ int width;
+
+ page.Row = 1;
+
+ if (SizeMode == TabSizeMode.Fixed) {
+ width = item_size.Width;
+ } else {
+ width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
+ }
+
+ if (i == SelectedIndex)
+ width += 8;
+ if (width < MinimumTabWidth)
+ width = MinimumTabWidth;
+
+ if (xpos + width > row_width && multiline) {
+ xpos = 4;
+ for (int j = 0; j < i; j++) {
+ TabPages [j].Row++;
+ }
+ row_count++;
+ } else if (xpos + width > row_width) {
+ show_slider = true;
+ }
+
+ xpos += width + 1 + spacing.Width;
+ }
+
+ if (SelectedIndex != -1 && TabPages [SelectedIndex].Row != BottomRow)
+ DropRow (TabPages [SelectedIndex].Row);
+ }
+
+ private int BottomRow {
+ get {
+ switch (Alignment) {
+ case TabAlignment.Right:
+ case TabAlignment.Bottom:
+ return row_count;
+ default:
+ return 1;
+ }
+ }
+ }
+
+ private int Direction
+ {
+ get {
+ switch (Alignment) {
+ case TabAlignment.Right:
+ case TabAlignment.Bottom:
+ return -1;
+ default:
+ return 1;
+ }
+ }
+ }
+
+ private void DropRow (int row)
+ {
+ int bottom = BottomRow;
+ int direction = Direction;
+
+ foreach (TabPage page in TabPages) {
+ if (page.Row == row) {
+ page.Row = bottom;
+ } else if (direction == 1 && page.Row < row) {
+ page.Row += direction;
+ } else if (direction == -1 && page.Row > row) {
+ page.Row += direction;
+ }
+ }
+ }
+
+ private int CalcYPos ()
+ {
+ if (Alignment == TabAlignment.Bottom) {
+ Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
+ return r.Bottom + 3;
+ }
+ return 1;
+ }
+
+ private int CalcXPos ()
+ {
+ if (Alignment == TabAlignment.Right) {
+ Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
+ return r.Right + 4;
+ }
+ return 4;
+
+ }
+
+ private void SizeTabs ()
+ {
+ switch (Alignment) {
+ case TabAlignment.Right:
+ case TabAlignment.Left:
+ SizeTabsV (Height);
+ break;
+ default:
+ SizeTabs (Width);
+ break;
+ }
+ }
+
+ private void SizeTabsV (int row_width)
+ {
+ int ypos = 1;
+ int prev_row = 1;
+ Size spacing = TabSpacing;
+ int xpos = CalcXPos ();
+ int begin_prev = 0;
+
+ if (TabPages.Count == 0)
+ return;
+
+ prev_row = TabPages [0].Row;
+
+ for (int i = 0; i < TabPages.Count; i++) {
+ TabPage page = TabPages [i];
+ int width;
+
+ if (SizeMode == TabSizeMode.Fixed) {
+ width = item_size.Width;
+ } else {
+ width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
+ }
+
+ if (width < MinimumTabWidth)
+ width = MinimumTabWidth;
+ if (page.Row != prev_row)
+ ypos = 1;
+
+ page.TabBounds = new Rectangle (xpos + (row_count - page.Row) * ((item_size.Height - 2) + spacing.Width),
+ ypos, item_size.Height - 2, width);
+
+ if (page.Row != prev_row) {
+ if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
+ FillRowV (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Bottom) / (i - begin_prev)), spacing);
+ }
+ begin_prev = i;
+ }
+
+ ypos += width + spacing.Width;
+ prev_row = page.Row;
+ }
+
+ if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
+ FillRowV (begin_prev, TabPages.Count - 1,
+ ((row_width - TabPages [TabPages.Count - 1].TabBounds.Bottom) / (TabPages.Count - begin_prev)), spacing);
+ }
+
+ if (SelectedIndex != -1) {
+ ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
+ }
+ }
+
+ private void SizeTabs (int row_width)
+ {
+ int ypos = CalcYPos ();
+ int prev_row = 1;
+ Size spacing = TabSpacing;
+ int xpos = 4;
+ int begin_prev = 0;
+
+ if (TabPages.Count == 0)
+ return;
+
+ prev_row = TabPages [0].Row;
+
+ // Reset the slider position if the slider isn't needed
+ // anymore (ie window size was increased so all tabs are visible)
+ if (!show_slider)
+ slider_pos = 0;
+
+ for (int i = slider_pos; i < TabPages.Count; i++) {
+ TabPage page = TabPages [i];
+ int width;
+
+ if (SizeMode == TabSizeMode.Fixed) {
+ width = item_size.Width;
+ } else {
+ width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
+ }
+
+ if (width < MinimumTabWidth)
+ width = MinimumTabWidth;
+ if (page.Row != prev_row)
+ xpos = 4;
+
+ page.TabBounds = new Rectangle (xpos,
+ ypos + (row_count - page.Row) * (item_size.Height + spacing.Height),
+ width, item_size.Height);
+
+ if (page.Row != prev_row) {
+ if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
+ FillRow (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Right) / (i - begin_prev)), spacing);
+ }
+ begin_prev = i;
+ }
+
+ xpos += width + 1 + spacing.Width;
+ prev_row = page.Row;
+ }
+
+ if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
+ FillRow (begin_prev, TabPages.Count - 1,
+ ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), spacing);
+ }
+
+ if (SelectedIndex != -1) {
+ ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
+ }
+ }
+
+ private void FillRow (int start, int end, int amount, Size spacing)
+ {
+ int xpos = TabPages [start].TabBounds.Left;
+ for (int i = start; i <= end; i++) {
+ TabPage page = TabPages [i];
+ int left = xpos;
+ int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
+
+ page.TabBounds = new Rectangle (left, page.TabBounds.Top,
+ width, page.TabBounds.Height);
+ xpos = page.TabBounds.Right + 1 + spacing.Width;
+ }
+ }
+
+ private void FillRowV (int start, int end, int amount, Size spacing)
+ {
+ int ypos = TabPages [start].TabBounds.Top;
+ for (int i = start; i <= end; i++) {
+ TabPage page = TabPages [i];
+ int top = ypos;
+ int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
+
+ page.TabBounds = new Rectangle (page.TabBounds.Left, top,
+ page.TabBounds.Width, height);
+ ypos = page.TabBounds.Bottom + 1;
+ }
+ }
+
+ private void ExpandSelected (TabPage page, int left_edge, int right_edge)
+ {
+ if (Appearance != TabAppearance.Normal)
+ return;
+
+ if (Alignment == TabAlignment.Top || Alignment == TabAlignment.Bottom) {
+ int l = page.TabBounds.Left - 4;
+ int r = page.TabBounds.Right + 4;
+ int y = page.TabBounds.Y;
+ int h = page.TabBounds.Height + 3;
+
+ if (l < left_edge)
+ l = left_edge;
+ if (r > right_edge && SizeMode != TabSizeMode.Normal)
+ r = right_edge;
+ if (Alignment == TabAlignment.Top)
+ y -= 1;
+ if (Alignment == TabAlignment.Bottom)
+ y -= 2;
+
+ page.TabBounds = new Rectangle (l, y, r - l, h);
+ } else {
+ int l = page.TabBounds.Left - 3;
+ int r = page.TabBounds.Right + 3;
+ int t = page.TabBounds.Top - 3;
+ int b = page.TabBounds.Bottom + 3;
+
+ if (t < left_edge)
+ t = left_edge;
+ if (b > right_edge)
+ b = right_edge;
+
+ page.TabBounds = new Rectangle (l, t, r - l, b - t);
+ }
+ }
+
+ private void PaintInternal (PaintEventArgs pe)
+ {
+ Draw (pe.Graphics, pe.ClipRectangle);
+ // On MS the Paint event never seems to be raised
+ }
+
+ private void Draw (Graphics dc, Rectangle clip)
+ {
+ ThemeEngine.Current.DrawTabControl (dc, clip, this);
+ }
+
+ private TabPage GetTab (int index)
+ {
+ return Controls [index] as TabPage;
+ }
+
+ private void SetTab (int index, TabPage value)
+ {
+ ((IList) Controls).Insert (index, value);
+ Redraw ();
+ }
+
+ internal void Redraw ()
+ {
+ ResizeTabPages ();
+ Refresh ();
+ }
+
+ #endregion // Internal & Private Methods
+
+ #region Events
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler BackColorChanged {
+ add { base.BackColorChanged += value; }
+ remove { base.BackColorChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler BackgroundImageChanged {
+ add { base.BackgroundImageChanged += value; }
+ remove { base.BackgroundImageChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler ForeColorChanged {
+ add { base.ForeColorChanged += value; }
+ remove { base.ForeColorChanged -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event PaintEventHandler Paint {
+ add { base.Paint += value; }
+ remove { base.Paint -= value; }
+ }
+
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new event EventHandler TextChanged {
+ add { base.TextChanged += value; }
+ remove { base.TextChanged -= value; }
+ }
+
+ public event DrawItemEventHandler DrawItem;
+ public event EventHandler SelectedIndexChanged;
+ #endregion // Events
+
+
+ #region Class TaControl.ControlCollection
+ public class ControlCollection : System.Windows.Forms.Control.ControlCollection {
+
+ private TabControl owner;
+ private ArrayList list = new ArrayList ();
+
+ public ControlCollection (TabControl owner) : base (owner)
+ {
+ this.owner = owner;
+ }
+
+ public override void Add (Control value)
+ {
+ if (!(value is TabPage))
+ throw new ArgumentException ("Cannot add " +
+ value.GetType ().Name + " to TabControl. " +
+ "Only TabPages can be directly added to TabControls.");
+
+ value.Visible = false;
+ base.Add (value);
+ if (Count == 1) {
+ owner.SelectedIndex = 0;
+ } else {
+ // Setting the selected index will calc the tab rows so
+ // we don't need to do it again
+ owner.ResizeTabPages ();
+ }
+ }
+
+ public override void Remove (Control value)
+ {
+ TabPage page = value as TabPage;
+ if (page != null) {
+ int index = owner.IndexForTabPage (page);
+ if (index == owner.SelectedIndex)
+ owner.SelectedIndex = (index + 1) % owner.TabCount;
+ }
+ base.Remove (value);
+ }
+ }
+ #endregion // Class TabControl.ControlCollection
+
+ #region Class TabPage.TabPageCollection
+ public class TabPageCollection : IList, ICollection, IEnumerable {
+
+ private TabControl owner;
+ private IList controls;
+
+ public TabPageCollection (TabControl owner)
+ {
+ if (owner == null)
+ throw new ArgumentNullException ("Value cannot be null.");
+ this.owner = owner;
+ controls = owner.Controls;
+ }
+
+ [Browsable(false)]
+ public virtual int Count {
+ get { return owner.Controls.Count; }
+ }
+
+ public virtual bool IsReadOnly {
+ get { return false; }
+ }
+
+ public virtual TabPage this [int index] {
+ get {
+ return owner.GetTab (index);
+ }
+ set {
+ owner.SetTab (index, value);
+ }
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot {
+ get { return this; }
+ }
+
+ bool IList.IsFixedSize {
+ get { return false; }
+ }
+
+ object IList.this [int index] {
+ get {
+ return owner.GetTab (index);
+ }
+ set {
+ owner.SetTab (index, (TabPage) value);
+ }
+ }
+
+ public void Add (TabPage page)
+ {
+ if (page == null)
+ throw new ArgumentNullException ("Value cannot be null.");
+ owner.Controls.Add (page);
+ }
+
+ public void AddRange (TabPage [] pages)
+ {
+ if (pages == null)
+ throw new ArgumentNullException ("Value cannot be null.");
+ owner.Controls.AddRange (pages);
+ }
+
+ public virtual void Clear ()
+ {
+ owner.Controls.Clear ();
+ }
+
+ public bool Contains (TabPage page)
+ {
+ if (page == null)
+ throw new ArgumentNullException ("Value cannot be null.");
+ return owner.Controls.Contains (page);
+ }
+
+ public virtual IEnumerator GetEnumerator ()
+ {
+ return owner.Controls.GetEnumerator ();
+ }
+
+ public int IndexOf (TabPage page)
+ {
+ return owner.Controls.IndexOf (page);
+ }
+
+ public void Remove (TabPage page)
+ {
+ owner.Controls.Remove (page);
+ }
+
+ public virtual void RemoveAt (int index)
+ {
+ owner.Controls.RemoveAt (index);
+ }
+
+ void ICollection.CopyTo (Array dest, int index)
+ {
+ owner.Controls.CopyTo (dest, index);
+ }
+
+ int IList.Add (object value)
+ {
+ TabPage page = value as TabPage;
+ if (value == null)
+ throw new ArgumentException ("value");
+ owner.Controls.Add (page);
+ return owner.Controls.IndexOf (page);
+ }
+
+ bool IList.Contains (object value)
+ {
+ TabPage page = value as TabPage;
+ if (page == null)
+ return false;
+ return Contains (page);
+ }
+
+ int IList.IndexOf (object value)
+ {
+ TabPage page = value as TabPage;
+ if (page == null)
+ return -1;
+ return IndexOf ((TabPage) page);
+ }
+
+ void IList.Insert (int index, object value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ void IList.Remove (object value)
+ {
+ TabPage page = value as TabPage;
+ if (page == null)
+ return;
+ Remove ((TabPage) value);
+ }
+ }
+ #endregion // Class TabPage.TabPageCollection
+ }
+}
+
+