Download Cyotek.Windows.Forms.TabList.zip version 1.0.0.2, last updated 31/12/2012 (152.27 KB)

Download
  • md5: fbf021a18c325e7384b409ad256a9207
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Cyotek.Windows.Forms.Design;

namespace Cyotek.Windows.Forms
{
  [ToolboxItem(true)]
  [Designer(typeof(TabListDesigner))]
  [DefaultProperty("TabListPages"), DefaultEvent("SelectedIndexChanged")]
  public partial class TabList
    : Control
  {
    #region  Private Member Declarations

    private Rectangle _displayRectangle;
    private Size _headerSize;
    private int _hoverIndex;
    private TabListPage[] _pages;
    private ITabListPageRenderer _renderer;
    private int _selectedIndex;
    private int _tabListPageCount;
    private TabListPageCollection _tabListPages;

    #endregion  Private Member Declarations

    #region  Static Constructors

    static TabList()
    {
      TabListPageRenderer.DefaultRenderer = new DefaultTabListPageRenderer();
    }

    #endregion  Static Constructors

    #region  Public Constructors

    public TabList()
    {
      // ReSharper disable DoNotCallOverridableMethodsInConstructor
      this.TabListPages = new TabListPageCollection(this);
      this.SelectedIndex = -1;
      this.HoverIndex = -1;
      this.HeaderSize = new Size(150, 25);
      this.Size = new Size(200, 200); // the default size is tiny!
      this.Padding = new Padding(3);
      this.DoubleBuffered = true;
      this.ShowTabList = true;
      this.AllowTabSelection = true;
      this.SetStyles();
      // ReSharper restore DoNotCallOverridableMethodsInConstructor
    }

    protected virtual void SetStyles()
    {
      this.SetStyle(ControlStyles.AllPaintingInWmPaint
                        | ControlStyles.ResizeRedraw
                        | ControlStyles.OptimizedDoubleBuffer
                        | ControlStyles.UserMouse
                        , true);
      this.SetStyle(ControlStyles.Selectable, this.AllowTabSelection);
    }

    #endregion  Public Constructors

    #region  Events

    [Category("Property Changed")]
    public event EventHandler HeaderSizeChanged;

    [Category("Property Changed")]
    public event EventHandler RendererChanged;

    [Category("Property Changed")]
    public event EventHandler SelectedIndexChanged;

    #endregion  Events

    #region  Overriden Properties

    public override Rectangle DisplayRectangle
    {
      get
      {
        if (_displayRectangle.IsEmpty)
        {
          int leftMargin;
          int topMargin;
          int rightMargin;
          int bottomMargin;

          // to avoid calculating every time, calculate it only when it's need it and cache it like any normal property
          if (this.ShowTabList)
            leftMargin = this.HeaderSize.Width + this.Padding.Left + 1;
          else
            leftMargin = this.Padding.Left + 1;
          topMargin = this.Padding.Top + 1;
          rightMargin = this.Padding.Right + 1;
          bottomMargin = this.Padding.Bottom + 1;

          _displayRectangle = new Rectangle(leftMargin, topMargin, this.ClientSize.Width - (leftMargin + rightMargin), this.ClientSize.Height - (topMargin + bottomMargin));
        }

        return _displayRectangle;
      }
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override string Text
    {
      get { return base.Text; }
      set { base.Text = value; }
    }

    #endregion  Overriden Properties

    #region  Protected Overridden Methods

    protected override Control.ControlCollection CreateControlsInstance()
    {
      return new TabListControlCollection(this);
    }

    protected override bool IsInputKey(Keys keyData)
    {
      bool result;

      switch (keyData)
      {
        case Keys.Up:
        case Keys.Down:
          result = true;
          break;
        default:
          result = base.IsInputKey(keyData);
          break;
      }

      return result;
    }

    protected override void OnGotFocus(EventArgs e)
    {
      base.OnGotFocus(e);

      this.Invalidate();
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
      base.OnKeyDown(e);

      if (this.ShowTabList)
      {
        // allow keyboard navigation, if any tabs are present
        if (this.TabListPageCount != 0)
        {
          switch (e.KeyCode)
          {
            case Keys.Down:
              this.CycleSelectedTab(1);
              break;
            case Keys.Up:
              this.CycleSelectedTab(-1);
              break;
            case Keys.PageDown:
              this.CycleSelectedTab(3);
              break;
            case Keys.PageUp:
              this.CycleSelectedTab(-3);
              break;
            case Keys.Home:
              this.SelectedIndex = 0;
              break;
            case Keys.End:
              this.SelectedIndex = this.TabListPageCount - 1;
              break;
          }
        }
      }
    }

    protected override void OnLostFocus(EventArgs e)
    {
      base.OnLostFocus(e);

      this.Invalidate();
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
      base.OnMouseClick(e);

      if (e.Button == MouseButtons.Left && (this.DesignMode | this.AllowTabSelection))
      {
        int index;

        index = this.GetItemAtPoint(e.Location);
        if (index != -1)
          this.SelectedIndex = index;
      }
    }

    protected override void OnMouseLeave(EventArgs e)
    {
      base.OnMouseLeave(e);

      this.HoverIndex = -1;
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      base.OnMouseMove(e);

      if (this.AllowTabSelection)
        this.HoverIndex = this.GetItemAtPoint(e.Location);
    }

    protected override void OnPaddingChanged(EventArgs e)
    {
      base.OnPaddingChanged(e);

      this.ResetSelectedPage();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      base.OnPaint(e);

      if (this.ShowTabList)
      {
        ITabListPageRenderer renderer;

        renderer = this.GetRenderer();

        for (int i = 0; i < this.TabListPageCount; i++)
        {
          TabListPageState state;

          if (i == this.SelectedIndex)
          {
            state = TabListPageState.Selected;
            if (this.Focused)
              state |= TabListPageState.Focused;
          }
          else if (i == this.HoverIndex)
            state = TabListPageState.Hot;
          else
            state = TabListPageState.Normal;

          renderer.RenderHeader(e.Graphics, this.TabListPages[i], state);
        }
      }
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);

      this.ResetSelectedPage();
    }

    #endregion  Protected Overridden Methods

    #region  Public Methods

    public virtual TabListPage HitTest(Point point)
    {
      int index;

      index = this.GetItemAtPoint(point);

      return index != -1 ? this.TabListPages[index] : null;
    }

    #endregion  Public Methods

    #region  Internal Methods

    internal int AddPage(TabListPage page)
    {
      int index;

      index = this.InsertPage(this.TabListPageCount, page);

      if (this.SelectedIndex == -1)
        this.SelectedIndex = index;

      return index;
    }

    internal void ClearAllPages()
    {
      this.Controls.Clear();
      _pages = null;
      this.TabListPageCount = 0;
    }

    internal TabListPage[] GetTabListPages()
    {
      TabListPage[] copy;

      copy = new TabListPage[this.TabListPageCount];

      if (this.TabListPageCount > 0)
        Array.Copy(_pages, copy, this.TabListPageCount);

      return copy;
    }

    internal int InsertPage(int index, TabListPage page)
    {
      if (_pages == null)
        _pages = new TabListPage[1];
      else if (_pages.Length == this.TabListPageCount)
      {
        // no room left, so resize the array
        TabListPage[] copy;

        copy = new TabListPage[_pages.Length + 1];
        Array.Copy(_pages, copy, _pages.Length);
        _pages = copy;
      }

      // if this is an insert rather than append, move the array around
      if (index < this.TabListPageCount)
        Array.Copy(_pages, index, _pages, index + 1, _pages.Length - index);

      // update the array and page count
      _pages[index] = page;
      this.TabListPageCount++;
      this.UpdatePages();
      this.UpdateSelectedPage();

      // finally trigger a redraw of the control
      this.Invalidate();

      return index;
    }

    internal void RemovePageAt(int index)
    {
      int selectedIndex;

      if ((index < 0) || (index >= this.TabListPageCount))
        throw new ArgumentOutOfRangeException("index", "");

      this.TabListPageCount--;

      if (index < this.TabListPageCount)
        Array.Copy(_pages, index + 1, _pages, index, this.TabListPageCount - index);

      _pages[this.TabListPageCount] = null;

      selectedIndex = this.SelectedIndex;
      if (this.TabListPageCount == 0)
        this.SelectedIndex = -1;
      else if (index == selectedIndex || selectedIndex >= this.TabListPageCount)
        this.SelectedIndex = 0;
      this.UpdatePages();
      this.UpdateSelectedPage();

      this.Invalidate();
    }

    internal void UpdatePage(TabListPage page)
    {
      this.Invalidate();
    }

    #endregion  Internal Methods

    #region  Public Properties

    [Category("Appearance"), DefaultValue(typeof(Size), "150, 25")]
    public virtual Size HeaderSize
    {
      get { return _headerSize; }
      set
      {
        if (this.HeaderSize != value)
        {
          _headerSize = value;

          this.OnHeaderSizeChanged(EventArgs.Empty);
        }
      }
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual int HoverIndex
    {
      get { return _hoverIndex; }
      set
      {
        if (_hoverIndex != value)
        {
          _hoverIndex = value;
          this.Invalidate();
        }
      }
    }

    [DefaultValue(typeof(Padding), "3, 3, 3, 3")]
    public new Padding Padding
    {
      get { return base.Padding; }
      set { base.Padding = value; }
    }

    [Category("Appearance"), DefaultValue(null)]
    public virtual ITabListPageRenderer Renderer
    {
      get { return _renderer; }
      set
      {
        if (this.Renderer != value)
        {
          _renderer = value;

          this.OnRendererChanged(EventArgs.Empty);
        }
      }
    }

    [Browsable(false), DefaultValue(-1), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual int SelectedIndex
    {
      get { return _selectedIndex; }
      set
      {
        if (this.SelectedIndex != value)
        {
          _selectedIndex = value;

          this.OnSelectedIndexChanged(EventArgs.Empty);
        }
      }
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual TabListPage SelectedPage
    {
      get { return this.SelectedIndex != -1 ? this.TabListPages[this.SelectedIndex] : null; }
      set { this.SelectedIndex = this.TabListPages.IndexOf(value); }
    }

    [Browsable(false)]
    public virtual int TabListPageCount
    {
      get { return _tabListPageCount; }
      protected set { _tabListPageCount = value; }
    }

    [Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual TabListPageCollection TabListPages
    {
      get { return _tabListPages; }
      protected set { _tabListPages = value; }
    }

    #endregion  Public Properties

    #region  Protected Methods

    protected virtual void CycleSelectedTab(int increment)
    {
      if (this.TabListPageCount != 0)
      {
        int index;

        index = this.SelectedIndex + increment;
        if (index < 0 && increment == -1 || index >= this.TabListPageCount && increment != 1)
          index = this.TabListPageCount - 1;
        else if (index < 0 && increment != -1 || index >= this.TabListPageCount && increment == 1)
          index = 0;

        this.SelectedIndex = index;
      }
    }

    protected virtual int GetItemAtPoint(Point point)
    {
      int result;

      result = -1;

      for (int i = 0; i < this.TabListPageCount; i++)
      {
        if (this.TabListPages[i].HeaderBounds.Contains(point))
        {
          result = i;
          break;
        }
      }

      return result;
    }

    protected virtual ITabListPageRenderer GetRenderer()
    {
      return this.Renderer ?? TabListPageRenderer.DefaultRenderer ?? new DefaultTabListPageRenderer();
    }

    protected virtual void OnHeaderSizeChanged(EventArgs e)
    {
      EventHandler handler;

      this.ResetSelectedPage();

      handler = this.HeaderSizeChanged;

      if (handler != null)
        handler(this, e);
    }

    protected virtual void OnRendererChanged(EventArgs e)
    {
      EventHandler handler;

      this.Invalidate();

      handler = this.RendererChanged;

      if (handler != null)
        handler(this, e);
    }

    protected virtual void OnSelectedIndexChanged(EventArgs e)
    {
      EventHandler handler;

      this.UpdateSelectedPage();

      handler = this.SelectedIndexChanged;

      if (handler != null)
        handler(this, e);
    }

    protected virtual void ResetSelectedPage()
    {
      _displayRectangle = Rectangle.Empty; // force the display rectangle to be recalculated
      this.UpdateSelectedPage();
    }

    protected virtual void UpdatePages()
    {
      int y;
      int x;

      y = this.Padding.Top;
      x = this.Padding.Left;

      foreach (TabListPage page in this.TabListPages)
      {
        page.HeaderBounds = new Rectangle(new Point(x, y), this.HeaderSize);
        y += this.HeaderSize.Height;
      }
    }

    protected virtual void UpdateSelectedPage()
    {
      if (this.SelectedIndex != -1)
      {
        this.SelectedPage.Bounds = this.DisplayRectangle;

        for (int i = 0; i < this.TabListPageCount; i++)
          _pages[i].Visible = (i == this.SelectedIndex);
      }

      this.Invalidate();
    }

    #endregion  Protected Methods

    private bool _showTabList;

    [Category("Appearance"), DefaultValue(true)]
    public virtual bool ShowTabList
    {
      get { return _showTabList; }
      set
      {
        if (this.ShowTabList != value)
        {
          _showTabList = value;

          this.OnShowTabListChanged(EventArgs.Empty);
        }
      }
    }

    /// <summary>
    /// Occurs when the ShowTabList property value changes
    /// </summary>
    [Category("Property Changed")]
    public event EventHandler ShowTabListChanged;

    /// <summary>
    /// Raises the <see cref="ShowTabListChanged" /> event.
    /// </summary>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected virtual void OnShowTabListChanged(EventArgs e)
    {
      EventHandler handler;

      this.ResetSelectedPage();

      handler = this.ShowTabListChanged;

      if (handler != null)
        handler(this, e);
    }

    private bool _allowTabSelection;

    [Category("Behavior"), DefaultValue(true)]
    public virtual bool AllowTabSelection
    {
      get { return _allowTabSelection; }
      set
      {
        if (this.AllowTabSelection != value)
        {
          _allowTabSelection = value;

          this.OnAllowTabSelectionChanged(EventArgs.Empty);
        }
      }
    }

    /// <summary>
    /// Occurs when the AllowTabSelection property value changes
    /// </summary>
    [Category("Property Changed")]
    public event EventHandler AllowTabSelectionChanged;

    /// <summary>
    /// Raises the <see cref="AllowTabSelectionChanged" /> event.
    /// </summary>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected virtual void OnAllowTabSelectionChanged(EventArgs e)
    {
      EventHandler handler;

      this.SetStyles();

      handler = this.AllowTabSelectionChanged;

      if (handler != null)
        handler(this, e);
    }


  }
}

Donate

Donate