aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Widgets/TabControl.cs
diff options
context:
space:
mode:
authorMichael VanOverbeek <[email protected]>2016-07-25 12:57:52 -0400
committerGitHub <[email protected]>2016-07-25 12:57:52 -0400
commit46c1c31302f111a1f3ec23a70e6f3986a9aa2a27 (patch)
treef00af7ea3f6ad2641fb26fa1d310fd8b7179b39c /source/ShiftUI/Widgets/TabControl.cs
parentaf48e774189596b8d7a058c564a7d6d75205ca03 (diff)
parent6fa16209519896de09949a27425dff00ebf2970a (diff)
downloadshiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.gz
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.bz2
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.zip
Merge pull request #17 from MichaelTheShifter/shiftui_integration
Shiftui integration
Diffstat (limited to 'source/ShiftUI/Widgets/TabControl.cs')
-rw-r--r--source/ShiftUI/Widgets/TabControl.cs2008
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
+ }
+}
+
+