diff options
Diffstat (limited to 'source/ShiftUI/Widgets/TabControl.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/TabControl.cs | 2008 |
1 files changed, 2008 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/TabControl.cs b/source/ShiftUI/Widgets/TabControl.cs new file mode 100644 index 0000000..0404510 --- /dev/null +++ b/source/ShiftUI/Widgets/TabControl.cs @@ -0,0 +1,2008 @@ +// 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 ([email protected]) + + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; +using ShiftUI.Theming; +using ShiftUI.VisualStyles; + +namespace ShiftUI { + [ComVisibleAttribute (true)] + [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("SelectedIndexChanged")] + [DefaultProperty("TabPages")] + //[Designer("ShiftUI.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class TabWidget : Widget { + #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 bool item_size_manual; + private Point padding; + private int row_count = 0; + private bool hottrack; + private TabPageCollection tab_pages; + private bool show_tool_tips; + private TabSizeMode size_mode; + private bool show_slider = false; + private PushButtonState right_slider_state = PushButtonState.Normal; + private PushButtonState left_slider_state = PushButtonState.Normal; + private int slider_pos = 0; + TabPage entered_tab_page; + bool mouse_down_on_a_tab_page; + ToolTip tooltip; + ToolTip.TipState tooltip_state = ToolTip.TipState.Down; + Timer tooltip_timer; + + private bool rightToLeftLayout; + #endregion // Fields + + #region UIA Framework Events + static object UIAHorizontallyScrollableChangedEvent = new object (); + + internal event EventHandler UIAHorizontallyScrollableChanged { + add { Events.AddHandler (UIAHorizontallyScrollableChangedEvent, value); } + remove { Events.RemoveHandler (UIAHorizontallyScrollableChangedEvent, value); } + } + + internal void OnUIAHorizontallyScrollableChanged (EventArgs e) + { + EventHandler eh + = (EventHandler) Events [UIAHorizontallyScrollableChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIAHorizontallyScrolledEvent = new object (); + + internal event EventHandler UIAHorizontallyScrolled { + add { Events.AddHandler (UIAHorizontallyScrolledEvent, value); } + remove { Events.RemoveHandler (UIAHorizontallyScrolledEvent, value); } + } + + internal void OnUIAHorizontallyScrolled (EventArgs e) + { + EventHandler eh + = (EventHandler) Events [UIAHorizontallyScrolledEvent]; + if (eh != null) + eh (this, e); + } + #endregion + + #region UIA Framework Property + internal double UIAHorizontalViewSize { + get { return LeftScrollButtonArea.Left * 100 / TabPages [TabCount - 1].TabBounds.Right; } + } + #endregion + + #region Public Constructors + public TabWidget () + { + tab_pages = new TabPageCollection (this); + SetStyle (Widgetstyles.UserPaint, false); + padding = ThemeEngine.Current.TabControlDefaultPadding; + + MouseDown += new MouseEventHandler (MouseDownHandler); + MouseLeave += new EventHandler (OnMouseLeave); + MouseMove += new MouseEventHandler (OnMouseMove); + 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 ThemeEngine.Current.ColorControl; } + set { /* nothing happens on set on MS */ } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + public override Rectangle DisplayRectangle { + get { + return ThemeEngine.Current.TabControlGetDisplayRectangle (this); + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { return base.DoubleBuffered; } + set { base.DoubleBuffered = value; } + } + + [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 (); + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue(null)] + public ImageList ImageList { + get { return image_list; } + set { + image_list = value; + Redraw (); + } + } + + [Localizable(true)] + public Size ItemSize { + get { + if (item_size_manual) + return item_size; + + if (!IsHandleCreated) + return Size.Empty; + + Size size = item_size; + if (SizeMode != TabSizeMode.Fixed) { + size.Width += padding.X * 2; + size.Height += padding.Y * 2; + } + + if (tab_pages.Count == 0) + size.Width = 0; + + return size; + } + set { + if (value.Height < 0 || value.Width < 0) + throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'."); + item_size = value; + item_size_manual = true; + 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 + new + 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 (); + } + + } + + [MonoTODO ("RTL not supported")] + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { return this.rightToLeftLayout; } + set { + if (value != this.rightToLeftLayout) { + this.rightToLeftLayout = value; + this.OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [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 (value < -1) { + throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " + + "'SelectedIndex' must be greater than or equal to -1."); + } + if (!this.IsHandleCreated) { + if (selected_index != value) { + selected_index = value; + } + return; + } + + if (value >= TabCount) { + if (value != selected_index) + OnSelectedIndexChanged (EventArgs.Empty); + return; + } + + if (value == selected_index) { + if (selected_index > -1) + Invalidate(GetTabRect (selected_index)); + return; + } + + TabControlCancelEventArgs ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Deselecting); + OnDeselecting (ret); + if (ret.Cancel) + return; + + Focus (); + int old_index = selected_index; + int new_index = value; + + selected_index = new_index; + + ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Selecting); + OnSelecting (ret); + if (ret.Cancel) { + selected_index = old_index; + return; + } + + SuspendLayout (); + + Rectangle invalid = Rectangle.Empty; + bool refresh = false; + + if (new_index != -1 && show_slider && new_index < slider_pos) { + slider_pos = new_index; + refresh = true; + } + + if (new_index != -1) { + int le = TabPages[new_index].TabBounds.Right; + int re = LeftScrollButtonArea.Left; + if (show_slider && le > re) { + int i = 0; + for (i = 0; i < new_index; i++) { + if (TabPages [i].TabBounds.Left < 0) // tab scrolled off the visible area, ignore + continue; + + if (TabPages [new_index].TabBounds.Right - TabPages[i].TabBounds.Right < re) { + i++; + break; + } + } + slider_pos = i; + refresh = true; + } + } + + if (old_index != -1 && new_index != -1) { + if (!refresh) + invalid = GetTabRect (old_index); + ((TabPage) Widgets[old_index]).SetVisible (false); + } + + TabPage selected = null; + + if (new_index != -1) { + selected = (TabPage) Widgets[new_index]; + invalid = Rectangle.Union (invalid, GetTabRect (new_index)); + selected.SetVisible (true); + } + + OnSelectedIndexChanged (EventArgs.Empty); + + ResumeLayout (); + + if (refresh) { + SizeTabs (); + Refresh (); + } else if (new_index != -1 && selected.Row != BottomRow) { + DropRow (TabPages[new_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 (but should not + // overflow the control bounds). + if (appearance == TabAppearance.Normal) { + invalid.Inflate (6, 4); + invalid.Intersect (ClientRectangle); + } + 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; + } + } + + [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; + } + } + + //[Editor ("ShiftUI.Design.TabPageCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + //[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; + + // UIA Framework Event: HorizontallyScrollable Changed + OnUIAHorizontallyScrollableChanged (EventArgs.Empty); + } + } + + internal int SliderPos { + get { return slider_pos; } + } + + internal PushButtonState RightSliderState { + get { return right_slider_state; } + private set { + if (right_slider_state == value) + return; + PushButtonState old_value = right_slider_state; + right_slider_state = value; + if (NeedsToInvalidateScrollButton (old_value, value)) + Invalidate (RightScrollButtonArea); + } + } + + internal PushButtonState LeftSliderState { + get { return left_slider_state; } + set { + if (left_slider_state == value) + return; + PushButtonState old_value = left_slider_state; + left_slider_state = value; + if (NeedsToInvalidateScrollButton (old_value, value)) + Invalidate (LeftScrollButtonArea); + } + } + + bool NeedsToInvalidateScrollButton (PushButtonState oldState, PushButtonState newState) + { + if ((oldState == PushButtonState.Hot && newState == PushButtonState.Normal) || + (oldState == PushButtonState.Normal && newState == PushButtonState.Hot)) + return HasHotElementStyles; + return true; + } + + internal TabPage EnteredTabPage { + get { return entered_tab_page; } + private set { + if (entered_tab_page == value) + return; + if (HasHotElementStyles) { + Region area_to_invalidate = new Region (); + area_to_invalidate.MakeEmpty (); + if (entered_tab_page != null) + area_to_invalidate.Union (entered_tab_page.TabBounds); + entered_tab_page = value; + if (entered_tab_page != null) + area_to_invalidate.Union (entered_tab_page.TabBounds); + Invalidate (area_to_invalidate); + area_to_invalidate.Dispose (); + } else + entered_tab_page = value; + + if (value == null) + CloseToolTip (); + else + SetToolTip (GetToolTipText (value)); + } + } + #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 Widget GetControl (int index) + { + return GetTab (index); + } + + public void SelectTab (TabPage tabPage) + { + if (tabPage == null) + throw new ArgumentNullException ("tabPage"); + + SelectTab (this.tab_pages [tabPage]); + } + + public void SelectTab (string tabPageName) + { + if (tabPageName == null) + throw new ArgumentNullException ("tabPageName"); + + SelectTab (this.tab_pages [tabPageName]); + } + + public void SelectTab (int index) + { + if (index < 0 || index > this.tab_pages.Count - 1) + throw new ArgumentOutOfRangeException ("index"); + + SelectedIndex = index; + } + + public void DeselectTab (TabPage tabPage) + { + if (tabPage == null) + throw new ArgumentNullException ("tabPage"); + + DeselectTab (this.tab_pages [tabPage]); + } + + public void DeselectTab (string tabPageName) + { + if (tabPageName == null) + throw new ArgumentNullException ("tabPageName"); + + DeselectTab (this.tab_pages [tabPageName]); + } + + public void DeselectTab (int index) + { + if (index == SelectedIndex) { + if (index >= 0 && index < this.tab_pages.Count - 1) + SelectedIndex = ++index; + else + SelectedIndex = 0; + } + } + + + 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 + + #region Handles + protected override Widget.WidgetCollection CreateWidgetsInstance () + { + return new TabWidget.WidgetCollection (this); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + selected_index = (selected_index >= TabCount ? (TabCount > 0 ? 0 : -1) : selected_index); + + if (TabCount > 0) { + if (selected_index > -1) + this.SelectedTab.SetVisible(true); + else + tab_pages[0].SetVisible(true); + } + ResizeTabPages (); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected override void Dispose (bool disposing) + { + CloseToolTip (); + base.Dispose (disposing); + } + + #endregion + + #region Events + protected virtual void OnDrawItem (DrawItemEventArgs e) + { + if (DrawMode != TabDrawMode.OwnerDrawFixed) + return; + + DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (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 virtual void OnSelectedIndexChanged (EventArgs e) + { + EventHandler eh = (EventHandler) (Events[SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + if (GetStyle (Widgetstyles.UserPaint)) + return; + + Draw (pe.Graphics, pe.ClipRectangle); + pe.Handled = true; + } + + protected override void OnEnter (EventArgs e) + { + base.OnEnter (e); + if (SelectedTab != null) + SelectedTab.FireEnter (); + } + + protected override void OnLeave (EventArgs e) + { + if (SelectedTab != null) + SelectedTab.FireLeave (); + base.OnLeave (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler) (Events[RightToLeftLayoutChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + + protected virtual void OnDeselecting (TabControlCancelEventArgs e) + { + TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[DeselectingEvent]); + if (eh != null) + eh (this, e); + + if (!e.Cancel) + OnDeselected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Deselected)); + } + + protected virtual void OnDeselected (TabControlEventArgs e) + { + TabControlEventHandler eh = (TabControlEventHandler) (Events[DeselectedEvent]); + if (eh != null) + eh (this, e); + + if (this.SelectedTab != null) + this.SelectedTab.FireLeave (); + } + + protected virtual void OnSelecting (TabControlCancelEventArgs e) + { + TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[SelectingEvent]); + if (eh != null) + eh (this, e); + + if (!e.Cancel) + OnSelected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Selected)); + } + + protected virtual void OnSelected (TabControlEventArgs e) + { + TabControlEventHandler eh = (TabControlEventHandler) (Events[SelectedEvent]); + if (eh != null) + eh (this, e); + + if (this.SelectedTab != null) + this.SelectedTab.FireEnter (); + } + + #endregion + + #region Keys + protected override bool ProcessKeyPreview (ref Message m) + { + return base.ProcessKeyPreview (ref m); + } + + protected override void OnKeyDown (KeyEventArgs ke) + { + base.OnKeyDown (ke); + if (ke.Handled) + return; + + if (ke.KeyCode == Keys.Tab && (ke.KeyData & Keys.Widget) != 0) { + if ((ke.KeyData & Keys.Shift) == 0) + SelectedIndex = (SelectedIndex + 1) % TabCount; + else + SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.PageUp && (ke.KeyData & Keys.Widget) != 0) { + SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.PageDown && (ke.KeyData & Keys.Widget) != 0) { + SelectedIndex = (SelectedIndex + 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.Home) { + SelectedIndex = 0; + ke.Handled = true; + } else if (ke.KeyCode == Keys.End) { + SelectedIndex = TabCount - 1; + ke.Handled = true; + } else if (NavigateTabs (ke.KeyCode)) + ke.Handled = true; + } + + protected override bool IsInputKey (Keys keyData) + { + switch (keyData & Keys.KeyCode) { + case Keys.Home: + case Keys.End: + case Keys.Left: + case Keys.Right: + case Keys.Up: + case Keys.Down: + return true; + } + return base.IsInputKey (keyData); + } + + private bool NavigateTabs (Keys keycode) + { + bool move_left = false; + bool move_right = false; + + if (alignment == TabAlignment.Bottom || alignment == TabAlignment.Top) { + if (keycode == Keys.Left) + move_left = true; + else if (keycode == Keys.Right) + move_right = true; + } else { + if (keycode == Keys.Up) + move_left = true; + else if (keycode == Keys.Down) + move_right = true; + } + + if (move_left) { + if (SelectedIndex > 0) { + SelectedIndex--; + return true; + } + } + + if (move_right) { + if (SelectedIndex < TabCount - 1) { + SelectedIndex++; + return true; + } + } + + return false; + } + #endregion + + #region Pages Collection + protected void RemoveAll () + { + Widgets.Clear (); + } + + protected virtual object [] GetItems () + { + TabPage [] pages = new TabPage [Widgets.Count]; + Widgets.CopyTo (pages, 0); + return pages; + } + + protected virtual object [] GetItems (Type baseType) + { + object[] pages = (object[])Array.CreateInstance (baseType, Widgets.Count); + Widgets.CopyTo (pages, 0); + return pages; + } + #endregion + + protected void UpdateTabSelection (bool updateFocus) + { + ResizeTabPages (); + } + + 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_SETFOCUS: + if (selected_index != -1) + Invalidate(GetTabRect(selected_index)); + base.WndProc (ref m); + break; + case Msg.WM_KILLFOCUS: + if (selected_index != -1) + Invalidate(GetTabRect(selected_index)); + base.WndProc (ref m); + break; + default: + base.WndProc (ref m); + break; + } + } + + #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 ((e.Button & MouseButtons.Left) == 0) + return; + + if (ShowSlider) { + Rectangle right = RightScrollButtonArea; + Rectangle left = LeftScrollButtonArea; + if (right.Contains (e.X, e.Y)) { + right_slider_state = PushButtonState.Pressed; + if (CanScrollRight) { + slider_pos++; + SizeTabs (); + + // UIA Framework Event: Horizontally Scrolled + OnUIAHorizontallyScrolled (EventArgs.Empty); + + switch (this.Alignment) { + case TabAlignment.Top: + Invalidate (new Rectangle (0, 0, Width, ItemSize.Height)); + break; + case TabAlignment.Bottom: + Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom)); + break; + case TabAlignment.Left: + Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height)); + break; + case TabAlignment.Right: + Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height)); + break; + } + + } else { + Invalidate (right); + } + return; + } else if (left.Contains (e.X, e.Y)) { + left_slider_state = PushButtonState.Pressed; + if (CanScrollLeft) { + slider_pos--; + SizeTabs (); + + // UIA Framework Event: Horizontally Scrolled + OnUIAHorizontallyScrolled (EventArgs.Empty); + + switch (this.Alignment) { + case TabAlignment.Top: + Invalidate (new Rectangle (0, 0, Width, ItemSize.Height)); + break; + case TabAlignment.Bottom: + Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom)); + break; + case TabAlignment.Left: + Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height)); + break; + case TabAlignment.Right: + Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height)); + break; + } + } else { + Invalidate (left); + } + return; + } + } + + int count = Widgets.Count; + for (int i = SliderPos; i < count; i++) { + if (!GetTabRect (i).Contains (e.X, e.Y)) + continue; + SelectedIndex = i; + mouse_down_on_a_tab_page = true; + break; + } + } + + private void MouseUpHandler (object sender, MouseEventArgs e) + { + mouse_down_on_a_tab_page = false; + if (ShowSlider && (left_slider_state == PushButtonState.Pressed || right_slider_state == PushButtonState.Pressed)) { + Rectangle invalid; + if (left_slider_state == PushButtonState.Pressed) { + invalid = LeftScrollButtonArea; + left_slider_state = GetScrollButtonState (invalid, e.Location); + } else { + invalid = RightScrollButtonArea; + right_slider_state = GetScrollButtonState (invalid, e.Location); + } + Invalidate (invalid); + } + } + + bool HasHotElementStyles { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.HasHotElementStyles (this); + } + } + + Rectangle LeftScrollButtonArea { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetLeftScrollRect (this); + } + } + + Rectangle RightScrollButtonArea { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetRightScrollRect (this); + } + } + + static PushButtonState GetScrollButtonState (Rectangle scrollButtonArea, Point cursorLocation) + { + return scrollButtonArea.Contains (cursorLocation) ? PushButtonState.Hot : PushButtonState.Normal; + } + + private void SizeChangedHandler (object sender, EventArgs e) + { + Redraw (); + } + + 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 Widgets) { + 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 = 0; + int ypos = 0; + Size spacing = TabSpacing; + + if (TabPages.Count > 0) + row_count = 1; + show_slider = false; + + CalculateItemSize (); + + for (int i = 0; i < TabPages.Count; i++) { + TabPage page = TabPages [i]; + int aux = 0; + SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, 0, ref aux, true); + } + + if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow) + DropRow (TabPages [SelectedIndex].Row); + } + + // ItemSize per-se is used mostly only to retrieve the Height, + // since the actual Width of the tabs is computed individually, + // except when SizeMode is TabSizeMode.Fixed, where Width is used as well. + private void CalculateItemSize () + { + if (item_size_manual) + return; + + SizeF size; + if (tab_pages.Count > 0) { + // .Net uses the first tab page if available. + size = TextRenderer.MeasureString (tab_pages [0].Text, Font); + + } else { + size = TextRenderer.MeasureString ("a", Font); + size.Width = 0; + } + + if (size_mode == TabSizeMode.Fixed) + size.Width = 96; + if (size.Width < MinimumTabWidth) + size.Width = MinimumTabWidth; + if (image_list != null && image_list.ImageSize.Height > size.Height) + size.Height = image_list.ImageSize.Height; + + item_size = size.ToSize (); + } + + private int BottomRow { + get { return 1; } + } + + private int Direction + { + get { + return 1; + } + } + + private void DropRow (int row) + { + if (Appearance != TabAppearance.Normal) + return; + + 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 || Alignment == TabAlignment.Left) + return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom; + + if (Appearance == TabAppearance.Normal) + return this.ClientRectangle.Y + ThemeEngine.Current.TabWidgetselectedDelta.Y; + + return this.ClientRectangle.Y; + + } + + private int CalcXPos () + { + if (Alignment == TabAlignment.Right) + return ThemeEngine.Current.TabControlGetPanelRect (this).Right; + + if (Appearance == TabAppearance.Normal) + return this.ClientRectangle.X + ThemeEngine.Current.TabWidgetselectedDelta.X; + + return this.ClientRectangle.X; + } + + private void SizeTabs () + { + switch (Alignment) { + case TabAlignment.Right: + case TabAlignment.Left: + SizeTabs (Height, true); + break; + default: + SizeTabs (Width, false); + break; + } + } + + private void SizeTabs (int row_width, bool vertical) + { + int ypos = 0; + int xpos = 0; + int prev_row = 1; + Size spacing = TabSpacing; + 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; + else { + // set X = -1 for marking tabs that are not visible due to scrolling + for (int i = 0; i < slider_pos; i++) { + TabPage page = TabPages[i]; + Rectangle x = page.TabBounds; + x.X = -1; + page.TabBounds = x; + } + } + + for (int i = slider_pos; i < TabPages.Count; i++) { + TabPage page = TabPages[i]; + SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false); + 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, vertical); + } + + if (SelectedIndex != -1) { + ExpandSelected (TabPages [SelectedIndex], 0, row_width - 1); + } + } + + private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos, + Size spacing, int prev_row, ref int begin_prev, bool widthOnly) + { + int width, height = 0; + + if (SizeMode == TabSizeMode.Fixed) { + width = item_size.Width; + } else { + width = MeasureStringWidth (DeviceContext, page.Text, Font); + width += (Padding.X * 2) + 2; + + if (ImageList != null && page.ImageIndex >= 0) { + width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X; + + int image_size = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y; + if (item_size.Height < image_size) + item_size.Height = image_size; + } + + if (width < MinimumTabWidth) + width = MinimumTabWidth; + } + + // Use ItemSize property to recover the padding info as well. + height = ItemSize.Height - ThemeEngine.Current.TabWidgetselectedDelta.Height; // full height only for selected tab + + if (i == SelectedIndex) + width += ThemeEngine.Current.TabWidgetselectedSpacing; + + if (widthOnly) { + page.TabBounds = new Rectangle (xpos, 0, width, 0); + page.Row = row_count; + if (xpos + width > row_width && multiline) { + xpos = 0; + row_count++; + } else if (xpos + width > row_width) { + show_slider = true; + } + if (i == selected_index && show_slider) { + for (int j = i-1; j >= 0; j--) { + if (TabPages [j].TabBounds.Left < xpos + width - row_width) { + slider_pos = j+1; + break; + } + } + } + } else { + if (page.Row != prev_row) { + xpos = 0; + } + + switch (Alignment) { + case TabAlignment.Top: + case TabAlignment.Bottom: + page.TabBounds = new Rectangle ( + xpos + CalcXPos (), + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (), + width, + height); + break; + case TabAlignment.Left: + if (Appearance == TabAppearance.Normal) { + // tab rows are positioned right to left + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (), + xpos, + height, + width); + } else { + // tab rows are positioned left to right + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (), + xpos, + height, + width); + } + + break; + case TabAlignment.Right: + if (Appearance == TabAppearance.Normal) { + // tab rows are positioned left to right + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (), + xpos, + height, + width); + } else { + // tab rows are positioned right to left + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (), + xpos, + height, + width); + } + + break; + } + + if (page.Row != prev_row) { + if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) { + bool vertical = alignment == TabAlignment.Right || alignment == TabAlignment.Left; + int offset = vertical ? TabPages [i - 1].TabBounds.Bottom : TabPages [i - 1].TabBounds.Right; + FillRow (begin_prev, i - 1, ((row_width - offset) / (i - begin_prev)), spacing, + vertical); + } + begin_prev = i; + } + } + + xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing; + } + + private void FillRow (int start, int end, int amount, Size spacing, bool vertical) + { + if (vertical) + FillRowV (start, end, amount, spacing); + else + FillRow (start, end, amount, spacing); + } + + 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; + + Rectangle r = page.TabBounds; + r.Y -= ThemeEngine.Current.TabWidgetselectedDelta.Y; + r.X -= ThemeEngine.Current.TabWidgetselectedDelta.X; + + r.Width += ThemeEngine.Current.TabWidgetselectedDelta.Width; + r.Height += ThemeEngine.Current.TabWidgetselectedDelta.Height; + if (r.Left < left_edge) + r.X = left_edge; + // Adjustment can't be used for right alignment, since it is + // the only one that has a different X origin than 0 + if (r.Right > right_edge && SizeMode != TabSizeMode.Normal && + alignment != TabAlignment.Right) + r.Width = right_edge - r.X; + page.TabBounds = r; + } + + private void Draw (Graphics dc, Rectangle clip) + { + ThemeEngine.Current.DrawTabControl (dc, clip, this); + } + + private TabPage GetTab (int index) + { + return Widgets [index] as TabPage; + } + + private void SetTab (int index, TabPage value) + { + if (!tab_pages.Contains (value)) { + this.Widgets.Add (value); + } + this.Widgets.RemoveAt (index); + this.Widgets.SetChildIndex (value, index); + Redraw (); + } + private void InsertTab (int index, TabPage value) + { + if (!tab_pages.Contains (value)) { + this.Widgets.Add (value); + } + this.Widgets.SetChildIndex (value, index); + Redraw (); + } + internal void Redraw () + { + if (!IsHandleCreated) + return; + + ResizeTabPages (); + Refresh (); + } + + private int MeasureStringWidth (Graphics graphics, string text, Font font) + { + if (text == String.Empty) + return 0; + StringFormat format = new StringFormat(); + RectangleF rect = new RectangleF(0, 0, 1000, 1000); + CharacterRange[] ranges = { new CharacterRange(0, text.Length) }; + Region[] regions = new Region[1]; + + format.SetMeasurableCharacterRanges(ranges); + format.FormatFlags = StringFormatFlags.NoClip; + format.FormatFlags |= StringFormatFlags.NoWrap; + regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format); + rect = regions[0].GetBounds(graphics); + + return (int)(rect.Width); + } + + void SetToolTip (string text) + { + if (!show_tool_tips) + return; + + if (text == null || text.Length == 0) { + CloseToolTip (); + return; + } + + if (tooltip == null) { + tooltip = new ToolTip (); + tooltip_timer = new Timer (); + tooltip_timer.Tick += new EventHandler (ToolTipTimerTick); + } + + CloseToolTip (); + + tooltip_state = ToolTip.TipState.Initial; + tooltip_timer.Interval = 500; + tooltip_timer.Start (); + } + + void CloseToolTip () + { + if (tooltip == null) + return; + + tooltip.Hide (this); + tooltip_timer.Stop (); + tooltip_state = ToolTip.TipState.Down; + } + + void ToolTipTimerTick (object o, EventArgs args) + { + switch (tooltip_state) { + case ToolTip.TipState.Initial: + tooltip_timer.Stop (); + tooltip_timer.Interval = 5000; + tooltip_timer.Start (); + tooltip_state = ToolTip.TipState.Show; + tooltip.Present (this, GetToolTipText (EnteredTabPage)); + break; + case ToolTip.TipState.Show: + CloseToolTip (); + break; + } + } + + void OnMouseMove (object sender, MouseEventArgs e) + { + if (!mouse_down_on_a_tab_page && ShowSlider) { + if (LeftSliderState == PushButtonState.Pressed || + RightSliderState == PushButtonState.Pressed) + return; + if (LeftScrollButtonArea.Contains (e.Location)) { + LeftSliderState = PushButtonState.Hot; + RightSliderState = PushButtonState.Normal; + EnteredTabPage = null; + return; + } + if (RightScrollButtonArea.Contains (e.Location)) { + RightSliderState = PushButtonState.Hot; + LeftSliderState = PushButtonState.Normal; + EnteredTabPage = null; + return; + } + LeftSliderState = PushButtonState.Normal; + RightSliderState = PushButtonState.Normal; + } + if (EnteredTabPage != null && EnteredTabPage.TabBounds.Contains (e.Location)) + return; + for (int index = 0; index < TabCount; index++) { + TabPage tab_page = TabPages[index]; + if (tab_page.TabBounds.Contains (e.Location)) { + EnteredTabPage = tab_page; + return; + } + } + EnteredTabPage = null; + } + + void OnMouseLeave (object sender, EventArgs e) + { + if (ShowSlider) { + LeftSliderState = PushButtonState.Normal; + RightSliderState = PushButtonState.Normal; + } + EnteredTabPage = null; + } + #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 BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= 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; } + } + + static object DrawItemEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + + public event DrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + static object SelectedEvent = new object (); + + public event TabControlEventHandler Selected { + add { Events.AddHandler (SelectedEvent, value); } + remove { Events.RemoveHandler (SelectedEvent, value); } + } + + static object DeselectedEvent = new object (); + + public event TabControlEventHandler Deselected + { + add { Events.AddHandler (DeselectedEvent, value); } + remove { Events.RemoveHandler (DeselectedEvent, value); } + } + + static object SelectingEvent = new object (); + + public event TabControlCancelEventHandler Selecting + { + add { Events.AddHandler (SelectingEvent, value); } + remove { Events.RemoveHandler (SelectingEvent, value); } + } + + static object DeselectingEvent = new object (); + + public event TabControlCancelEventHandler Deselecting + { + add { Events.AddHandler (DeselectingEvent, value); } + remove { Events.RemoveHandler (DeselectingEvent, value); } + } + + static object RightToLeftLayoutChangedEvent = new object (); + public event EventHandler RightToLeftLayoutChanged + { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + #endregion // Events + + + #region Class TaControl.ControlCollection + [ComVisible (false)] + public new class ControlCollection : Widget.WidgetCollection { + + private TabWidget owner; + + public ControlCollection (TabWidget owner) : base (owner) + { + this.owner = owner; + } + + public override void Add (Widget value) + { + TabPage page = value as TabPage; + if (page == null) + throw new ArgumentException ("Cannot add " + + value.GetType ().Name + " to TabControl. " + + "Only TabPages can be directly added to TabWidgets."); + + page.SetVisible (false); + base.Add (value); + if (owner.TabCount == 1 && owner.selected_index < 0) + owner.SelectedIndex = 0; + owner.Redraw (); + } + + public override void Remove (Widget value) + { + bool change_index = false; + + TabPage page = value as TabPage; + if (page != null && owner.Widgets.Contains (page)) { + int index = owner.IndexForTabPage (page); + if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1) + change_index = true; + } + + base.Remove (value); + + // We don't want to raise SelectedIndexChanged until after we + // have removed from the collection, so TabCount will be + // correct for the user. + if (change_index && Count > 0) { + // Clear the selected index internally, to avoid trying to access the previous + // selected tab when setting the new one - this is what .net seems to do + int prev_selected_index = owner.SelectedIndex; + owner.selected_index = -1; + + owner.SelectedIndex = --prev_selected_index; + owner.Invalidate (); + } else if (change_index) { + owner.selected_index = -1; + owner.OnSelectedIndexChanged (EventArgs.Empty); + owner.Invalidate (); + } else + owner.Redraw (); + } + } + #endregion // Class TabControl.ControlCollection + + #region Class TabPage.TabPageCollection + public class TabPageCollection : IList, ICollection, IEnumerable { + + private TabWidget owner; + + public TabPageCollection (TabWidget owner) + { + if (owner == null) + throw new ArgumentNullException ("Value cannot be null."); + this.owner = owner; + } + + [Browsable(false)] + public int Count { + get { return owner.Widgets.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual TabPage this [int index] { + get { + return owner.GetTab (index); + } + set { + owner.SetTab (index, value); + } + } + public virtual TabPage this [string key] { + get { + if (string.IsNullOrEmpty (key)) + return null; + + int index = this.IndexOfKey (key); + if (index < 0 || index >= this.Count) + return null; + + return this[index]; + } + } + + internal int this[TabPage tabPage] { + get { + if (tabPage == null) + return -1; + + for (int i = 0; i < this.Count; i++) + if (this[i].Equals (tabPage)) + return i; + + return -1; + } + } + + 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 value) + { + if (value == null) + throw new ArgumentNullException ("Value cannot be null."); + owner.Widgets.Add (value); + } + + public void Add (string text) + { + TabPage page = new TabPage (text); + this.Add (page); + } + + public void Add (string key, string text) + { + TabPage page = new TabPage (text); + page.Name = key; + this.Add (page); + } + + public void Add (string key, string text, int imageIndex) + { + TabPage page = new TabPage (text); + page.Name = key; + page.ImageIndex = imageIndex; + this.Add (page); + } + + // .Net sets the ImageKey, but does not show the image when this is used + public void Add (string key, string text, string imageKey) + { + TabPage page = new TabPage (text); + page.Name = key; + page.ImageKey = imageKey; + this.Add (page); + } + + public void AddRange (TabPage [] pages) + { + if (pages == null) + throw new ArgumentNullException ("Value cannot be null."); + owner.Widgets.AddRange (pages); + } + + public virtual void Clear () + { + owner.Widgets.Clear (); + owner.Invalidate (); + } + + public bool Contains (TabPage page) + { + if (page == null) + throw new ArgumentNullException ("Value cannot be null."); + return owner.Widgets.Contains (page); + } + + public virtual bool ContainsKey (string key) + { + int index = this.IndexOfKey (key); + return (index >= 0 && index < this.Count); + } + + public IEnumerator GetEnumerator () + { + return owner.Widgets.GetEnumerator (); + } + + public int IndexOf (TabPage page) + { + return owner.Widgets.IndexOf (page); + } + + public virtual int IndexOfKey(string key) + { + if (string.IsNullOrEmpty (key)) + return -1; + + for (int i = 0; i < this.Count; i++) { + if (string.Compare (this[i].Name, key, true, + System.Globalization.CultureInfo.InvariantCulture) == 0) { + return i; + } + } + + return -1; + } + + public void Remove (TabPage value) + { + owner.Widgets.Remove (value); + owner.Invalidate (); + } + + public void RemoveAt (int index) + { + owner.Widgets.RemoveAt (index); + owner.Invalidate (); + } + + public virtual void RemoveByKey (string key) + { + int index = this.IndexOfKey (key); + if (index >= 0 && index < this.Count) + this.RemoveAt (index); + } + + void ICollection.CopyTo (Array dest, int index) + { + owner.Widgets.CopyTo (dest, index); + } + + int IList.Add (object value) + { + TabPage page = value as TabPage; + if (value == null) + throw new ArgumentException ("value"); + owner.Widgets.Add (page); + return owner.Widgets.IndexOf (page); + } + + bool IList.Contains (object page) + { + TabPage tabPage = page as TabPage; + if (tabPage == null) + return false; + return Contains (tabPage); + } + + int IList.IndexOf (object page) + { + TabPage tabPage = page as TabPage; + if (tabPage == null) + return -1; + return IndexOf (tabPage); + } + + void IList.Insert (int index, object tabPage) + { + throw new NotSupportedException (); + } + + public void Insert (int index, string text) + { + owner.InsertTab (index, new TabPage (text)); + } + + public void Insert (int index, TabPage tabPage) + { + owner.InsertTab (index, tabPage); + } + + public void Insert (int index, string key, string text) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + } + + public void Insert (int index, string key, string text, int imageIndex) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + page.ImageIndex = imageIndex; + } + + public void Insert (int index, string key, string text, string imageKey) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + page.ImageKey = imageKey; + } + void IList.Remove (object value) + { + TabPage page = value as TabPage; + if (page == null) + return; + Remove ((TabPage) value); + } + } + #endregion // Class TabPage.TabPageCollection + } +} + + |
