vbAccelerator - Contents of code file: acclExplorerBar_acclExplorerBar.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Resources;
using System.Windows.Forms;
using vbAccelerator.Components.Controls.ExplorerBarUtility;
using vbAccelerator.Components.Controls.ExplorerBarFramework;

namespace vbAccelerator.Components.Controls
{

   #region Delegates
   /// <summary>
   /// Represents the method that handles the <see
    cref="acclExplorerBar.BarClick" /> event.
   /// </summary>
   public delegate void ExplorerBarClickEventHandler(object sender,
    ExplorerBarClickEventArgs args);
   /// <summary>
   /// Represents the method that handles the <see
    cref="acclExplorerBar.ItemClick" /> event.
   /// </summary>
   public delegate void ExplorerBarItemClickEventHandler(object sender,
    ExplorerBarItemClickEventArgs args);
   /// <summary>
   /// Represnets the method that handles the <see
    cref="acclExplorerBar.NonBarClick"/> event.
   /// </summary>
   public delegate void ExplorerBarClickBaseEventHandler (object sender,
    ExplorerBarClickBaseEventArgs args); 
   #endregion

   #region Enums
   /// <summary>
   /// Drawing Style options for the Explorer Bar control.  These options
   /// configure which type of drawing is performed depending on the 
   /// underlying OS.
   /// </summary>
   public enum ExplorerBarDrawingStyle : int
   {
      /// <summary>
      /// Use the current system's style to draw the 
      /// ExplorerBar (will be either classic or XP)
      /// </summary>
      System,
      /// <summary>
      /// Always use XP style (emulated if no XP styles available)
      /// </summary>
      XP,
      /// <summary>
      /// Always draw in Windows Classic style.
      /// </summary>
      Classic,
      /// <summary>
      /// Use XP style but customise colours to suit
      /// </summary>
      Custom
   }

   /// <summary>
   /// Explorer Bar modes.
   /// </summary>
   public enum ExplorerBarMode : int
   {
      /// <summary>
      /// The default Explorer Bar mode.  In this mode the Explorer
      /// bar renders a series of disconnected bars each of which
      /// have their own title.
      /// </summary>
      Default,
      /// <summary>
      /// Search Explorer Bar mode.  In this mode, bars are joined
      /// together within a single frame.
      /// </summary>
      Search
   }
   
   /// <summary>
   /// The state of a bar.
   /// </summary>
   public enum ExplorerBarState : int
   {
      /// <summary>
      /// Bar is collapsed.
      /// </summary>
      Collapsed,
      /// <summary>
      /// Bar is expanded.
      /// </summary>
      Expanded
   }

   /// <summary>
   /// Processing performed on the Watermark bitmap before
   /// it is displayed in an Explorer Bar background
   /// </summary>
   public enum ExplorerBarWatermarkMode : int
   {
      /// <summary>
      /// The Watermark is colourised to match the background
      /// colour of the bar.
      /// </summary>
      Colourise,
      /// <summary>
      /// The Watermark is rendered directly without any processing.
      /// </summary>
      Direct
   }

   /// <summary>
   /// Alignment of a Watermark within the Explorer Bar control.
   /// </summary>
   public enum ExplorerBarWatermarkAlignment : int
   {
      /// <summary>
      /// The Watermark is aligned to the near margin of the bar.
      /// </summary>
      Near,
      /// <summary>
      /// The Watermark is centred in the bar.
      /// </summary>
      Center,
      /// <summary>
      /// The Watermark is aligned to the far margin of the bar.
      /// </summary>
      Far
   }

   /// <summary>
   /// Types of ExplorerBar items
   /// </summary>
   public enum ExplorerBarItemType : int
   {
      /// <summary>
      /// A clickable textual link with an optional icon
      /// </summary>
      Link,
      /// <summary>
      /// Non-clickable text only.
      /// </summary>
      Text,
      /// <summary>
      /// Non-clickable image.
      /// </summary>
      Image,
      /// <summary>
      /// A place where a control can be added.
      /// </summary>
      ControlPlaceHolder
   }
   #endregion

   /// <summary>
   /// An implementation of an XP Windows Explorer style side bar 
   /// control.  An Explorer Bar can be used in two ways:
   /// <list type="number">
   /// <item>
   /// <description>To show contextual task information for the currently
    selected 
   /// item in the UI.  Each bar can be expanded and collapsed to allow the user
   /// to customise which information is shown.
   ///  </description>
   /// </item>
   /// <item>
   /// <description>To contain groupings of controls, some of which (for
    example, 
   /// representing advanced options) can be hidden by collapsing the bar that
   /// the item belongs to.
   /// </description>
   /// </item>
   /// </list>
   /// The control can operate either drawing the Explorer style, using
    underlying
   /// XP theme information if available, or it can draw using an emulated style
   /// which is customisable.  The implementation of the control opens the 
   /// internal API for extension for bars with customised graphics.
   /// </summary>
   public class acclExplorerBar : ControllableScrollableControl
   {
      #region Events
      /// <summary>
      /// Event raised when a bar's title is clicked.
      /// </summary>
      public event ExplorerBarClickEventHandler BarClick;
      /// <summary>
      /// Event raised when an item is clicked.
      /// </summary>
      public event ExplorerBarItemClickEventHandler ItemClick;
      /// <summary>
      /// Event raised when a non-bar area of the control is clicked.
      /// </summary>
      public event ExplorerBarClickBaseEventHandler NonBarClick;
      #endregion

      #region Enums
      private enum ExplorerBarFocusReason
      {
         FocusByKey,
         FocusByMouse
      }
      #endregion

      #region Member Variables
      private ExplorerBarDrawingStyle drawingStyle =
       ExplorerBarDrawingStyle.System;
      private ExplorerBarMode drawingMode = ExplorerBarMode.Default;
      private bool showFocusRect = true;
      private XpThemeAPI xpTheme;
      private BarBitmaps barBitmaps;
      private Color backColorStart = Color.Empty;
      private Color backColorEnd = Color.Empty;
      private ImageList itemImageList = null;
      private ImageList titleImageList = null;
      private bool redraw = true;
      private ExplorerBarCollection bars = null;
      private ToolTip toolTip = null;
      private int lastWidth = 0;
      private int lastHeight = 0;
      private int internalBorder = 12;
      private IExplorerBarControlItem mouseOverItem = null;
      private IExplorerBarControlItem mouseDownItem = null;
      private Hashtable focusFakers = new Hashtable();
      private Hashtable focusFakerItems = new Hashtable();
      private ExplorerBarFocusReason focusReason =
       ExplorerBarFocusReason.FocusByMouse;
      private IExplorerBarControlItem focusItem = null;
      private bool barAnimations = true;
      private Bitmap animBitmap = null;
      private Point lastCursorPosition;

      /// <summary> 
      /// Required designer variable.
      /// </summary>
      private System.ComponentModel.Container components = null;
      #endregion

      /// <summary>
      /// Constructs a new instance of the Explorer Bar control.
      /// </summary>
      public acclExplorerBar()
      {
         // This call is required by the Windows.Forms Form Designer.
         InitializeComponent();

         FocusFaker faker = new FocusFaker(this);
         faker.Left = -faker.Width * 2;
         faker.Top = -faker.Height * 2;
         focusFakers.Add(this, faker);
         focusFakerItems.Add(faker, this);
         Controls.Add(faker);

         // I am a tab stop in the form:
         base.TabStop = true;
         // Set the styles to make things draw properly:
         base.SetStyle(
            ControlStyles.AllPaintingInWmPaint |
            ControlStyles.DoubleBuffer |
            ControlStyles.ResizeRedraw |
            ControlStyles.ContainerControl, 
            true);
         xpTheme = new XpThemeAPI();
         barBitmaps = new BarBitmaps();

         bars = new ExplorerBarCollection(this);
      }

      /// <summary> 
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if(components != null)
            {
               components.Dispose();
            }
         }
         base.Dispose( disposing );
      }

      #region Component Designer generated code
      /// <summary> 
      /// Required method for Designer support - do not modify 
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
         // 
         // acclExplorerBar
         // 
         this.Name = "acclExplorerBar";

      }
      #endregion


      #region Public Properties
      /// <summary>
      /// Gets whether the control is currently showing the focus rectangle or
       not.
      /// </summary>
      public bool ShowingFocusRectangle
      {
         get
         {
            return (focusReason == ExplorerBarFocusReason.FocusByKey);
         }
      }

      /// <summary>
      /// Gets or sets a <see cref="ToolTip"/> to associate 
      /// with the control.
      /// </summary>
      public System.Windows.Forms.ToolTip ToolTip
      {
         get
         {
            return toolTip;
         }
         set
         {
            toolTip = value;
         }
      }
      /// <summary>
      /// Gets the collection of bars associated with this
      /// control.
      /// </summary>
      public ExplorerBarCollection Bars
      {
         get
         {
            return bars;
         }
      }
      /// <summary>
      /// Gets/sets whether the control is redrawing or not.
      /// </summary>
      public bool Redraw
      {
         get
         {
            return redraw;
         }
         set
         {
            if (redraw != value)
            {
               redraw = value;
               if (value)
               {
                  Invalidate();
               }
            }
         }
      }
      /// <summary>
      /// Gets/sets the drawing style that will be used by the
      /// ExplorerBar control.
      /// </summary>
      public ExplorerBarDrawingStyle DrawingStyle
      {
         get
         {
            return drawingStyle;
         }
         set
         {
            drawingStyle = value;
            DrawingStyleChanged(new EventArgs());
         }
      }

      /// <summary>
      /// Gets/sets the Explorer Bar mode.
      /// </summary>
      public ExplorerBarMode Mode
      {
         get
         {
            return drawingMode;
         }
         set
         {
            drawingMode = value;
            DrawingStyleChanged(new EventArgs());
         }
      }

      /// <summary>
      /// Gets/sets whether the focus rectangle should be shown for bars
      /// and items in the control.
      /// </summary>
      public bool ShowFocusRect
      {
         get
         {
            return showFocusRect;
         }
         set
         {
            showFocusRect = value;
            Invalidate();
         }
      }

      /// <summary>
      /// Gets/sets the start colour of the background
      /// gradient when drawing using XPEmulated mode.
      /// Set to <c>Color.Empty</c> for default colours.
      /// </summary>
      public Color BackColorStart
      {
         get
         {
            return backColorStart;
         }
         set
         {
            backColorStart = value;
            Invalidate();
         }
      }
      /// <summary>
      /// Gets/sets the end colour of the background
      /// gradient when drawing using XPEmulated mode.
      /// Set to <c>Color.Empty</c> for default colours.
      /// </summary>
      public Color BackColorEnd
      {
         get
         {
            return backColorEnd;
         }
         set
         {
            backColorEnd = value;
            Invalidate();
         }
      }

      /// <summary>
      /// Gets/sets the ImageList used to draw icons for
      /// items within bars.
      /// </summary>
      public System.Windows.Forms.ImageList ImageList
      {
         get
         {
            return itemImageList;
         }
         set
         {
            itemImageList = value;
            Invalidate();
         }
      }

      /// <summary>
      /// Gets/sets the ImageList used to draw icons in
      /// the bar titles.
      /// </summary>
      public System.Windows.Forms.ImageList TitleImageList
      {
         get
         {
            return titleImageList;
         }
         set
         {
            titleImageList = value;
            Invalidate();
         }
      }

      /// <summary>
      /// Gets/sets whether bar state changes are animated or not.
      /// </summary>
      public bool AnimateStateChanges
      {
         get
         {
            return barAnimations;
         }
         set
         {
            barAnimations = value;
         }
      }

      #endregion

      #region Overrides
      /// <summary>
      /// Processes a mnemonic key press.
      /// </summary>
      /// <param name="charCode">Character code for the key press</param>
      /// <returns><c>true</c> if processed, <c>false</c> otherwise.</returns>
      protected override bool ProcessMnemonic(
         Char charCode )
      {
         bool processed = false;
         foreach (ExplorerBar bar in bars)
         {
            if (bar.ContainsMnemonic(charCode))
            {
               bar.Focused = true;
               OnBarClick(new ExplorerBarClickEventArgs(bar, MouseButtons.None,
                PointToClient(Cursor.Position)));
               processed = true;
               break;
            }
            else
            {
               foreach (ExplorerBarItem item in bar.Items)
               {
                  if (item.ContainsMnemonic(charCode))
                  {
                     item.Focused = true;
                     OnItemClick(new ExplorerBarItemClickEventArgs(item,
                      MouseButtons.None, PointToClient(Cursor.Position)));
                     processed = true;
                     break;
                  }
               }
            }
         }
         if (processed)
         {
            return true;
         }
         else
         {
            return base.ProcessMnemonic(charCode);
         }
      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.GotFocus"/> event
       and ensures that
      /// the focus rectangle is displayed when necessary.
      /// </summary>
      /// <param name="e">Not used.</param>
      protected override void OnGotFocus(
         EventArgs e
         )
      {
         base.OnGotFocus(e);

         if (ExplorerBarHelper.KeyIsPressed(Keys.Tab))
         {
            focusReason = ExplorerBarFocusReason.FocusByKey;
         }
         else
         {
            focusReason = ExplorerBarFocusReason.FocusByMouse;
         }

         // Find first bar and set the focus to it:
         if (bars.Count > 0)
         {
            if (ExplorerBarHelper.KeyIsPressed(Keys.ShiftKey))
            {
               bars[bars.Count-1].Focused = true;
            }
            else
            {
               bars[0].Focused = true;
            }
         }

      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.MouseMove"/> event
      /// and performs internal mouse move processing.
      /// </summary>
      /// <param name="e"><see cref="MouseEventArgs"/> describing
      /// the MouseMove event</param>
      protected override void OnMouseMove(
         MouseEventArgs e
         )
      {
         base.OnMouseMove(e);         
         
         if (e.Button == MouseButtons.None)
         {
            // Check whether the mouse actually moved
            if (Cursor.Position != lastCursorPosition)
            {
               Point location = new Point(e.X, e.Y);

               ExplorerBar bar = HitTestBar(location);
               if (bar != null)
               {
                  bar.MouseOver = true;
                  setToolTip(bar.ToolTipText);
               }
               else
               {
                  ExplorerBarItem item = HitTestItem(location);
                  if (item != null)
                  {
                     item.MouseOver = true;
                     setToolTip(item.ToolTipText);
                  }
                  else
                  {
                     InternalOnItemMouseOver(null);
                     setToolTip("");
                  }
               }
            }
            if ((mouseOverItem != null) && (mouseOverItem.Clickable))
            {               
               ResourceManager resources = new
                ResourceManager(typeof(acclExplorerBar));               
               Cursor = (Cursor) (resources.GetObject("Hand"));
            }
            else
            {
               Cursor = Cursors.Default;
            }
            lastCursorPosition = Cursor.Position;
         }
      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.MouseDown"/> event
      /// and performs internal mouse down processing.
      /// </summary>
      /// <param name="e"><see cref="MouseEventArgs"/> describing
      /// the MouseDown event</param>
      protected override void OnMouseDown(
         MouseEventArgs e
         )
      {
         base.OnMouseDown(e);
         
         Point location = new Point(e.X, e.Y);

         ExplorerBar bar = HitTestBar(location);
         if (bar != null)
         {
            bar.MouseOver = true;
            bar.MouseDown = true;
         }
         else
         {
            ExplorerBarItem item = HitTestItem(location);
            if (item != null)
            {
               item.MouseOver = true;
               item.MouseDown = true;
            }
            else
            {
               if (mouseOverItem != null)
               {
                  mouseOverItem.MouseOver = false;
               }
            }
         }


      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.MouseUp"/> event
      /// and performs internal mouse up processing.
      /// </summary>
      /// <param name="e"><see cref="MouseEventArgs"/> describing
      /// the MouseUp event</param>
      protected override void OnMouseUp(
         MouseEventArgs e
         )
      {
         base.OnMouseUp(e);

         Point location = new Point(e.X, e.Y);
         bool actionned = false;
         
         if (mouseDownItem != null)
         {
            if (mouseDownItem.HitTest(location, ClientRectangle.Width,
             VerticalScrollBar.Visible))
            {
               mouseDownItem.Focused = true;
               ActionFocusItem(e.Button, location);
               actionned = true;
            }
         }
         
         if (!actionned)
         {
            // general click somewhere
            OnNonBarClick(new ExplorerBarClickBaseEventArgs(e.Button,
             location));
         }
         
         if (mouseDownItem != null)
         {
            mouseDownItem.MouseDown = false;
            mouseDownItem = null;
         }

      }

      private void ActionFocusItem()
      {
         ActionFocusItem(MouseButtons.None, PointToClient(Cursor.Position));
      }

      private void ActionFocusItem(MouseButtons button, Point location)
      {
         if (focusItem != null)
         {            
            if (focusItem.Clickable)
            {
               if (typeof(ExplorerBar).IsAssignableFrom(focusItem.GetType()))
               {
                  if (
                     ((button == MouseButtons.None) || (button ==
                      MouseButtons.Left))
                     && (focusItem.Clickable))
                  {
                     InternalChangeBarState((ExplorerBar) focusItem);
                  }
                  OnBarClick(new ExplorerBarClickEventArgs((ExplorerBar)
                   focusItem, button, location));
               }
               else
               {
                  OnItemClick(new
                   ExplorerBarItemClickEventArgs((ExplorerBarItem) focusItem,
                   button, location));
               }
            }
         }
      }         

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.MouseLeave"/> event
      /// and performs internal mouse leave processing.
      /// </summary>
      /// <param name="e">Not used</param>
      protected override void OnMouseLeave(
         EventArgs e
         )
      {
         base.OnMouseLeave(e);
         if (mouseOverItem != null)
         {
            mouseOverItem.MouseOver = false;
            mouseOverItem = null;
         }
      }

      /// <summary>
      /// Raises the <see cref="Control.SizeChanged"/> event and re-evaluates
      /// the items in the control if necessary.
      /// </summary>
      /// <param name="e"></param>
      protected override void OnSizeChanged(
         EventArgs e
         )
      {
         if (bars.Count > 0)
         {
            if (Width != lastWidth)
            {         
               Graphics graphics = Graphics.FromHwnd(Handle);
               ExplorerBarMeasureItemParams measureItemParams =
                MeasureItemParams(graphics);
               foreach (ExplorerBar bar in bars)
               {
                  bar.InternalMeasureItem(measureItemParams);
               }
               graphics.Dispose();
            
               lastWidth = Width;
               
               Invalidate();
            }

            if (Height != lastHeight)
            {               
               SetScroll();
               lastHeight = Height;
            }
         }

         base.OnSizeChanged(e);
      }

      /// <summary>
      /// Determines whether the specified key should be
      /// processed by the control.
      /// </summary>
      /// <param name="keyData">Information about the key.</param>
      /// <returns><c>true</c> if th control processes the key,
      /// otherwise <c>false</c>.</returns>
      protected override bool IsInputKey(
         System.Windows.Forms.Keys keyData)
      {
         bool ret = false;
         switch (keyData)
         {
            case Keys.Up:
            case Keys.Down:
            case Keys.Right:
            case Keys.Left:
            case Keys.Enter:
            case Keys.Tab:
               ret = true;
               break;
            default:
               ret = base.IsInputKey(keyData);
               break;
         }         
         return ret;
      }   

      /// <summary>
      /// Handles system colour changes and raises the
       <c>SystemColorsChanged</c>
      /// event.
      /// </summary>
      /// <param name="e">Not used</param>
      protected override void OnSystemColorsChanged ( EventArgs e )
      {
         base.OnSystemColorsChanged(e);

         DrawingStyleChanged(e);
         Invalidate();
      }

      /// <summary>
      /// Raises the <c>Scroll</c> event for the control and updates
      /// the display.
      /// </summary>
      /// <param name="e">Scroll event information.</param>
      protected override void OnScroll(ControllableScrollEventArgs e)
      {
         base.OnScroll(e);
         Invalidate();
      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.HandleCreated"/>
       event and 
      /// performs activities related to building the control's
      /// style.
      /// </summary>
      /// <param name="e">Not used.</param>
      protected override void OnHandleCreated(EventArgs e)
      {
         base.OnHandleCreated(e);

         DrawingStyleChanged(e);
      }

      /// <summary>
      /// Raises the <see cref="System.Windows.Forms.Control.Paint"/> event and
       paints the control.
      /// </summary>
      /// <param name="e">Information about the painting event to
       perform</param>
      protected override void OnPaint(PaintEventArgs e)
      {
         if (redraw)
         {

            // Draw the background of the control:         
            xpTheme.DrawBackground(e.Graphics, 
               base.ClientRectangle, 
               drawingStyle,
               backColorStart,
               backColorEnd);

            ExplorerBarDrawItemParams drawItemParams =
             DrawItemParams(e.Graphics);

            int top = drawItemParams.Top;
            int height = 0;
            if (drawingMode == ExplorerBarMode.Search)
            {
               foreach (ExplorerBar bar in bars)
               {
                  height += drawItemParams.ScrollShowing ? bar.HeightWithScroll
                   : bar.HeightWithoutScroll;
                  height += internalBorder;               
               }
               ExplorerBarHelper.DrawSearchContainer(
                  e.Graphics, base.ClientRectangle, drawItemParams.Top, height,
                   internalBorder,
                  barBitmaps.NormalPanelColor);
            }

            // Now paint the bars:
            top = drawItemParams.Top;
            foreach (ExplorerBar bar in bars)
            {               
               // Change top for next item
               height = drawItemParams.ScrollShowing ? bar.HeightWithScroll :
                bar.HeightWithoutScroll;
               if ((top < ClientRectangle.Height) && (top + height >= 0))
               {
                  bar.InternalDrawItem(drawItemParams);
               }
               else
               {
                  bar.InternalMakeControlsVisible(false);
               }
               top += height;
               top += internalBorder;
               drawItemParams.SetTop(top);
            }
         }
      }
      #endregion

      #region Overridable subs
      /// <summary>
      /// Raises the <see cref="BarClick"/> event.
      /// </summary>
      /// <param name="e">Event arguments relating to the bar that was
       clicked</param>
      protected virtual void OnBarClick(ExplorerBarClickEventArgs e)
      {
         if (BarClick != null)
         {
            BarClick(this, e);
         }
      }

      /// <summary>
      /// Raises the <see cref="ItemClick"/> event.
      /// </summary>
      /// <param name="e">Event arguments relating to the item that was
       clicked</param>
      protected virtual void OnItemClick(ExplorerBarItemClickEventArgs e)
      {
         e.Item.Click();
         if (ItemClick != null)
         {
            ItemClick(this, e);
         }
      }

      /// <summary>
      /// Raises the <see cref="NonBarClick"/> event.
      /// </summary>
      /// <param name="e">Event arguments relating to the click</param>
      protected virtual void OnNonBarClick(ExplorerBarClickBaseEventArgs e)
      {
         if (NonBarClick != null)
         {
            NonBarClick(this, e);
         }
      }

      private void DrawingStyleChanged(EventArgs e)
      {
         // Get the right XP Theme:
         xpTheme.Handle = base.Handle;
         xpTheme.ClassList = "ExplorerBar";

         // Get the appropriate bitmaps:
         barBitmaps.Load(base.Handle, drawingStyle);

         // Colourise any watermarks that we need to
         foreach (ExplorerBar bar in bars)
         {
            if (bar.Watermark != null)
            {
               if (bar.WatermarkMode == ExplorerBarWatermarkMode.Colourise)
               {
                  InternalOnBarWatermarkChanged(bar);
               }
            }
         }

         // Redraw the control with the new changes in place
         Invalidate();

      }
      #endregion

      #region Internal implementation
      internal void InternalOnItemMouseOver(IExplorerBarControlItem item)
      {
         if (mouseOverItem != null)
         {
            if (mouseOverItem != item)
            {
               mouseOverItem.MouseOver = false;
            }
         }
         mouseOverItem = item;
      }

      internal void InternalOnItemMouseDown(IExplorerBarControlItem item)
      {
         if (mouseDownItem != null)
         {
            if (mouseDownItem != item)
            {
               mouseDownItem.MouseDown = false;
            }
         }
         mouseDownItem = item;
      }

      internal void InternalOnItemFocus(IExplorerBarControlItem item)
      {
         if (focusItem != null)
         {
            if (focusItem != item)
            {
               focusItem.Focused = false;               
            }
         }
         focusItem = item;
      }

      /// <summary>
      /// Measures an item which has been added to a bar and resizes the 
      /// control to fit.
      /// </summary>
      /// <param name="item">Item which has just been added.</param>
      internal void InternalOnItemAdd(ExplorerBarItem item)
      {
         ExplorerBar bar = bars.BarForItem(item);         
         Debug.Assert(bar != null, "InternalOnItemAdd called for item which
          does not belong to a bar");

         // Note; currently remeasuring all items in the bar.
         // could be more efficient by just measuring the added
         if (bar != null)
         {
            Graphics graphics = Graphics.FromHwnd(Handle);
            ExplorerBarMeasureItemParams measureItemParams =
             MeasureItemParams(graphics);
            bar.InternalMeasureItem(measureItemParams);
            graphics.Dispose();

            // Check size ok
            SetScroll();

            // Only need to invalidate the bar and any subsequent bars
            Invalidate();
         }
         
      }

      /// <summary>
      /// When an item has a control, the bar loads an internal control to
       follow it
      /// to ensure that focus is passed on in the correct order.  This routine 
      /// corrects the internal state of the control whenever an item's control
       is
      /// changed.
      /// </summary>
      /// <param name="item">Item who's control is changed</param>
      /// <param name="oldControl">Previous control associated with the item, or
      /// <c>null</c> if no control.</param>
      /// <param name="newControl">New control associated with the item, or
      /// <c>null</c> if no control.</param>
      public void OnItemControlChanged(ExplorerBarItem item, Control
       oldControl, Control newControl)
      {
         FocusFaker faker = null;
         if (oldControl != null)
         {
            if (focusFakers.ContainsKey(oldControl))
            {
               focusFakerItems.Remove(item);
               faker = (FocusFaker) focusFakers[oldControl];
               Controls.Remove(faker);
               focusFakers.Remove(oldControl);
               faker.Dispose();
               faker = null;
            }
            oldControl.Visible = false;
         }
         if (newControl != null)
         {
            Controls.Add(newControl);
            faker = new FocusFaker(this);
            faker.Left = -faker.Width * 2;
            faker.Top = -faker.Height * 2;
            focusFakers.Add(newControl, faker);
            focusFakerItems.Add(faker, item);
            Controls.Add(faker);
         }
      }

      /// <summary>
      /// Remeasures the control in response to the size of an
      /// item changing and redraws.
      /// </summary>
      /// <param name="item">Item which has changed size.</param>
      internal void InternalOnItemSizeChanged(ExplorerBarItem item)
      {
         //Console.WriteLine("OnItemSizeChanged");
      }

      /// <summary>
      /// Redraws an item.
      /// </summary>
      /// <param name="item">Item to redraw.</param>
      internal void InternalOnItemRedraw(ExplorerBarItem item)
      {
         // Only actually need to invalidate the item:
         Invalidate();
      }

      /// <summary>
      /// Remeasures the control in response to the size of a 
      /// bar changing and redraws.
      /// </summary>
      /// <param name="bar">Bar which has changed size.</param>
      internal void InternalOnBarResized(ExplorerBar bar)
      {
         // Make sure the control is remeasured:
         Graphics graphics = Graphics.FromHwnd(Handle);
         ExplorerBarMeasureItemParams measureItemParams =
          MeasureItemParams(graphics);
         foreach (ExplorerBar otherBar in bars)
         {
            otherBar.InternalMeasureItem(measureItemParams);
         }
         graphics.Dispose();
         SetScroll();
         Invalidate();
      }

      internal void InternalEnsureVisible(ExplorerBar bar)
      {
         if (VerticalScrollBar.Visible)
         {
            int top = 0;
            int height = 0;
            foreach (ExplorerBar testBar in bars)
            {
               height =  testBar.HeightWithScroll + internalBorder;
               if (bar == testBar)
               {
                  if (top < VerticalScrollBar.Value)
                  {
                     VerticalScrollBar.Value = top;
                     Invalidate();
                  }
                  else if (top + height + 6 > ClientRectangle.Height +
                   VerticalScrollBar.Value)
                  {
                     // Can we fit the entire bar in 
                     if ((height + 6) < ClientRectangle.Height)
                     {
                        // Yes
                        VerticalScrollBar.Value = (top + height + 6) -
                         ClientRectangle.Height;
                        Invalidate();
                     }
                     else
                     {
                        // No 
                        VerticalScrollBar.Value = top;
                        Invalidate();
                     }
                  }
                  break;
               }
               top += height;
            }

         }
      }


      internal void InternalEnsureVisible(ExplorerBarItem item)
      {
         if (VerticalScrollBar.Visible)
         {
            int top = -VerticalScrollBar.Value;
            int height = 0;
            foreach (ExplorerBar testBar in bars)
            {
               height =  testBar.HeightWithScroll;
               if (testBar.Items.Contains(item))
               {
                  // locate the top of the item:
                  if (top < 0)
                  {
                     VerticalScrollBar.Value += top + 12;
                  }
                  else if (top + height > ClientRectangle.Height)
                  {
                     VerticalScrollBar.Value = top + height + 12;
                  }
                  break;
               }
               top += height;
               top += internalBorder;
            }
         }
      }

      internal void InternalKeyDown(FocusFaker faker, KeyEventArgs e)
      {
         IExplorerBarControlItem candidate = null;
         switch (e.KeyCode)
         {
            case Keys.Up:
               candidate = FindNextCandidate(focusItem, true);   
               break;
            case Keys.Down:
               candidate = FindNextCandidate(focusItem, false);
               break;
         }
         if (candidate != null)
         {
            candidate.Focused = true;
         }

      }

      private IExplorerBarControlItem FindNextCandidate(
         IExplorerBarControlItem currentItem,
         bool upwards
         )
      {
         IExplorerBarControlItem candidate = null;
         if (focusItem == null)
         {
            candidate = FindCandidateTabItem(false);
         }
         else
         {
            ExplorerBar bar;
            if (typeof(ExplorerBarItem).IsAssignableFrom(currentItem.GetType()))
            {
               // Item is currently focused
               ExplorerBarItem item = (ExplorerBarItem) currentItem;
               bar = item.Bar;
               if (upwards)
               {
                  if (bar.State == ExplorerBarState.Expanded)
                  {
                     candidate = bar.Items.PreviousFocusableItem(item);
                  }
                  if (candidate == null)
                  {
                     candidate = bar;
                  }
               }
               else
               {
                  if (bar.State == ExplorerBarState.Expanded)
                  {
                     candidate = item.Bar.Items.NextFocusableItem(item);
                  }
                  if (candidate == null)
                  {
                     candidate = bars.Next(bar);
                  }
               }
            }
            else
            {
               // Bar is current focused
               candidate = FindCandidateTabItem(currentItem, upwards);
            }
         }
         return candidate;
      }

      /// <summary>
      /// Determine what to do if a focus faker gets the input key
      /// </summary>
      /// <param name="focusFrom">Control with focus</param>
      internal void InternalGotFocus(FocusFaker focusFrom)
      {         
         IExplorerBarControlItem candidate = null;

         Object item = focusFakerItems[focusFrom];
         if (item == null)
         {
            return;
         }
         if (typeof(acclExplorerBar).IsAssignableFrom(item.GetType()))
         {
            // The control has received input focus
            if (focusItem != null)
            {
               focusItem.Focused = false;
               focusItem = null;
            }
            candidate =
             FindCandidateTabItem(ExplorerBarHelper.KeyIsPressed(Keys.ShiftKey))
            ;
         }
         else
         {
            // A control inside this control has just lost input focus
            IExplorerBarControlItem lastItem = (IExplorerBarControlItem) item;
            candidate = FindNextCandidate(lastItem,
             ExplorerBarHelper.KeyIsPressed(Keys.ShiftKey));
         }

         if (candidate != null)
         {
            focusItem = candidate;
            focusItem.Focused = true;   
         }

      }

      /// <summary>
      /// Determine if the key is an input key.
      /// </summary>
      /// <param name="focusFrom">Control with focus</param>
      /// <param name="keyData">Keys to parse</param>
      /// <returns><c>true</c> if the key is an input key, <c>false</c>
       otherwise.</returns>
      internal bool InternalIsInputKey(FocusFaker focusFrom,
       System.Windows.Forms.Keys keyData)
      {   
         focusReason = ExplorerBarFocusReason.FocusByKey;
         bool isInputKey = false;
         
         if ((keyData == Keys.Tab) || (keyData == (Keys.Tab | Keys.Shift)))
         {
            IExplorerBarControlItem candidate = FindCandidateTabItem(focusFrom, 
               (keyData & Keys.Shift) == Keys.Shift);
            if (candidate != null)
            {
               candidate.Focused = true;
               isInputKey = true;
            }
            else
            {
               if (focusItem != null)
               {
                  focusItem.Focused = false;
               }
            }
            if (focusReason != ExplorerBarFocusReason.FocusByKey)
            {
               focusReason = ExplorerBarFocusReason.FocusByKey;
               Invalidate();
            }
         }
         else
         {
            if (focusItem != null)
            {
               if (focusItem.Clickable)
               {
                  ActionFocusItem();
                  isInputKey = true;
               }
            }
         }

         return isInputKey;
      }

      /// <summary>
      /// Finds the the next item to tab to given a tab event in
      /// the specified focus control.
      /// </summary>
      /// <param name="focusFrom">Focus control in which tab event
       occurred</param>
      /// <param name="upwards">Whether to search upwards or not</param>
      /// <returns>Item if found, null otherwise</returns>
      private IExplorerBarControlItem FindCandidateTabItem(
         FocusFaker focusFrom,
         bool upwards
         )
      {
         IExplorerBarControlItem candidate = null;
         
         // Find next focus candidate:
         
         // Firstly, is anything focused:
         if (focusItem == null)
         {
            Object focused = focusFakerItems[focusFrom];
            if (typeof(ExplorerBarItem).IsAssignableFrom(focused.GetType()))
            {
               // focus item is for an item
               IExplorerBarControlItem startItem = (IExplorerBarControlItem)
                focused;
               candidate = FindCandidateTabItem(startItem, upwards);
            }
            else
            {
               // focus item represents the control
               candidate = FindCandidateTabItem(upwards);
            }
         }
         else
         {
            // something previously focused in the control
            candidate = FindCandidateTabItem(focusItem, upwards);
         }

         return candidate;
      }

      /// <summary>
      /// Finds the next candidate tab item when nothing has been focused
      /// </summary>
      /// <param name="upwards">Whether to search upwards or downwards</param>
      /// <returns>Item if found, null otherwise </returns>
      private IExplorerBarControlItem FindCandidateTabItem(
         bool upwards
         )
      {
         IExplorerBarControlItem candidate = null;
         // Nothing currently in focus, find first bar or last item
         if (upwards)
         {
            // last item
            int index = bars.Count - 1;
            while ((candidate == null) && (index >= 0))
            {
               if (bars[index].State == ExplorerBarState.Expanded)
               {
                  candidate = bars[index].Items.FindLastFocusableItem();
               }
               if (candidate == null)
               {
                  if (bars[index].Clickable)
                  {
                     candidate = bars[index];
                  }
               }
               index--;
            }
         }
         else
         {
            int index = 0;
            while ((candidate == null) && (index < bars.Count))
            {
               if (bars[index].Clickable)
               {
                  candidate = bars[index];
               }
               else
               {
                  if (bars[index].State == ExplorerBarState.Expanded)
                  {
                     candidate = bars[index].Items.FindFirstFocusableItem();
                  }
               }
               index++;
            }
         }
         return candidate;
      }

      private IExplorerBarControlItem FindCandidateTabItem(
         IExplorerBarControlItem firstItem,
         bool upwards
         )
      {
         IExplorerBarControlItem candidate = null;

         if (typeof(ExplorerBarItem).IsAssignableFrom(firstItem.GetType()))
         {
            // item focused, find next or previous bar
            ExplorerBarItem item = (ExplorerBarItem) firstItem;
            ExplorerBar bar = item.Bar;
            bool found = false;
            if (upwards)
            {
               while (!found)
               {
                  candidate = bar;
                  if (!candidate.Clickable)
                  {
                     candidate = bar.Items.FindLastFocusableItem();
                     if (candidate == null)
                     {
                        bar = bars.Previous(bar);
                        found = (bar == null);
                     }
                     else
                     {
                        found = true;
                     }
                  }
                  else
                  {
                     found = true;
                  }
               }               
            }
            else
            {            
               while (!found)
               {
                  candidate = bars.Next(bar);
                  if (candidate != null)
                  {
                     if (!candidate.Clickable)
                     {
                        bar = (ExplorerBar) candidate;
                        candidate = null;
                        candidate = bar.Items.FindFirstFocusableItem();
                        if (candidate == null)
                        {
                           bar = bars.Next(bar);
                           found = (bar == null);
                        }
                        else
                        {
                           found = true;
                        }
                     }
                     else
                     {
                        found = true;
                     }
                  }
                  else
                  {
                     found = true;
                  }
               }
            }
         }
         else
         {
            // bar focused, find first item in bar or last item in previous bar
            ExplorerBar bar = (ExplorerBar) firstItem;
            if (upwards)
            {
               bar = bars.Previous(bar);
               if (bar != null)
               {
                  if (bar.State == ExplorerBarState.Expanded)
                  {
                     candidate = bar.Items.FindLastFocusableItem();
                  }
                  if (candidate == null)
                  {
                     candidate = bar;
                  }
               }
            }
            else
            {
               if (bar.State == ExplorerBarState.Expanded)
               {
                  candidate = bar.Items.FindFirstFocusableItem();
               }
               if (candidate == null)
               {
                  candidate = bars.Next(bar);
               }
            }
         }
         
         return candidate;
      }

      /// <summary>
      /// Finds the focus item which the specified focus fake control
      /// has been added for.
      /// </summary>
      /// <param name="focusFrom">Focus Fake control</param>
      /// <returns>Item which the control was added for.</returns>
      private IExplorerBarControlItem FindItemForFocusFaker(FocusFaker
       focusFrom)
      {
         IExplorerBarControlItem theItem = null;
         Object item = focusFakers[focusFrom];
         if (typeof(IExplorerBarControlItem).IsAssignableFrom(item.GetType()))
         {
            theItem = (IExplorerBarControlItem) item;
         }
         return theItem;
      }

      /// <summary>
      /// Clears up any internal variables which refer to an
      /// Bar being removed from the ExplorerBar.
      /// </summary>
      /// <param name="bar">Bar to remove</param>
      internal void InternalOnBarRemoved(ExplorerBar bar)
      {
         if (mouseOverItem == bar)
         {
            mouseOverItem = null;
         }
         if (mouseDownItem == bar)
         {
            mouseDownItem = null;
         }
         if (focusItem == bar)
         {
            focusItem = null;
         }
         InternalOnBarResized(bar);
      }

      /// <summary>
      /// Clears up any internal variables which refer to an
      /// Item being removed from the ExplorerBar.
      /// </summary>
      /// <param name="item">Item to remove</param>
      internal void InternalOnItemRemoved(ExplorerBarItem item)
      {
         if (mouseOverItem == item)
         {
            mouseOverItem = null;
         }
         if (mouseDownItem == item)
         {
            mouseDownItem = null;
         }
         if (focusItem == item)
         {
            focusItem = null;
         }
         // Make sure the control is remeasured:
         InternalOnBarResized(item.Bar);
      }

      internal ExplorerBar InternalBarForItem(ExplorerBarItem item)
      {
         return bars.BarForItem(item);
      }

      /// <summary>
      /// Ensures a bar has the correct title colours and 
      /// redraws it.
      /// </summary>
      /// <param name="bar">Bar to redraw</param>
      internal void InternalOnBarRedraw(ExplorerBar bar)
      {
         // Ensure the bar bitmaps have the right colours:
         if (bar.IsSpecial)
         {
            barBitmaps.SpecialTitleColorDark = bar.TitleBackColorEnd;
            barBitmaps.SpecialTitleColorLight = bar.TitleBackColorStart;
         }
         else
         {
            barBitmaps.NormalTitleColorDark = bar.TitleBackColorEnd;
            barBitmaps.NormalTitleColorLight = bar.TitleBackColorStart;
         }
         // Only actually need to invalidate the bar in question
         Invalidate();
      }

      /// <summary>
      /// Ensures the watermark bitmap for a bar is colourised according
      /// to the current display settings.
      /// </summary>
      /// <param name="bar">Bar to colourise watermark for</param>
      internal void InternalOnBarWatermarkChanged(ExplorerBar bar)
      {
         Debug.Assert(bar != null, "InternalOnBarWatermarkChanged called with
          null bar parameter");
         Debug.Assert(bar.Watermark != null, "InternalOnBarWatermarkChanged
          called for bar without watermark");
         bar.ProcessedWatermark = (Bitmap) bar.Watermark.Clone();      
         Color backColor = ExplorerBarHelper.BarBackColor(
            bar.BackColor, drawingStyle, barBitmaps, xpTheme, bar.IsSpecial);
         ImageUtility.ColouriseWatermark(bar.ProcessedWatermark, backColor);
         Invalidate();
      }

      /// <summary>
      /// Gets the object which manages the currently selected XP theme.
      /// </summary>
      internal XpThemeAPI XpTheme
      {
         get
         {
            return xpTheme;
         }
      }

      /// <summary>
      /// Gets the object which manages the bitmaps to display for
      /// bar titles and buttons.
      /// </summary>
      internal BarBitmaps Bitmaps
      {
         get
         {
            return barBitmaps;
         }
      }
      #endregion

      #region Private implementation
      /// <summary>
      /// Sets the mouse down flag for the specified item,
      /// clearing any existing focus or mouse over items
      /// </summary>
      /// <param name="item">Item to set MouseDown flag on</param>
      private void SetMouseDown(ExplorerBarItem item)
      {
         item.MouseDown = true;
         item.Focused = true;
      }


      /// <summary>
      /// Changes the state of a Bar from expanded to collapsed or
      /// vice-versa, animating the bar if configured to do so.
      /// </summary>
      /// <param name="bar">Bar to change state</param>
      internal void InternalChangeBarState(ExplorerBar bar)
      {
         // Determine from & to for the bar change operation
         bool scroll = VerticalScrollBar.Visible;
         int currentHeight = 0;
         int targetHeight = 0;
         if (bar.State == ExplorerBarState.Expanded)
         {
            currentHeight = (scroll ? bar.HeightWithScroll :
             bar.HeightWithoutScroll);
            targetHeight = (scroll ? bar.TitleHeightWithScroll :
             bar.TitleHeightWithoutScroll);
            bar.InternalSetState(ExplorerBarState.Collapsed);
         }
         else
         {
            currentHeight = (scroll ? bar.TitleHeightWithScroll :
             bar.TitleHeightWithoutScroll);
            bar.InternalSetState(ExplorerBarState.Expanded);
            targetHeight = (scroll ? bar.HeightWithScroll :
             bar.HeightWithoutScroll);
         }
         double direction = Math.Sign(targetHeight - currentHeight);
         SetScroll();

         if ((bar.AnimateStateChanges) && (barAnimations))
         {
            // Create a memory bitmap to draw onto:
            Bitmap bm = new Bitmap(ClientRectangle.Width, (currentHeight >
             targetHeight ? currentHeight : targetHeight));
            // Clone it so it actually is 32bpp Argb
            animBitmap = bm.Clone(new Rectangle(0, 0, bm.Width, bm.Height),
               PixelFormat.Format32bppArgb);
            bm.Dispose();

            bar.SetAnimationInformation((direction > 0), (direction < 0));
            int nowHeight = currentHeight;
            int step = (int) direction;
            step *= Math.Max(1, bar.Items.Count / 2);
            int alpha = 255;
            while (nowHeight != targetHeight)
            {
               nowHeight += step;
               if (direction > 0)
               {
                  alpha = (255 * (nowHeight - currentHeight)) / (targetHeight -
                   currentHeight);
                  bar.SetAnimationOffset((nowHeight - targetHeight), alpha);
               }
               else
               {
                  alpha = (255 * (nowHeight - targetHeight)) / (currentHeight -
                   targetHeight);
                  bar.SetAnimationOffset((nowHeight - currentHeight), alpha);
               }

               // Show new version
               Invalidate();
               Update();

               step = (int) (step + direction);
               direction *= 1.25;
               if (direction > 0)
               {
                  if (nowHeight + step > targetHeight)
                  {
                     step = targetHeight - nowHeight;
                  }
               }
               else
               {
                  if (nowHeight + step < targetHeight)
                  {
                     step = targetHeight - nowHeight;
                  }
               }
            }            
            
            bar.SetAnimationInformation(false, false);
            animBitmap.Dispose();
            animBitmap = null;
         }

         bar.EnsureVisible();
         Invalidate();

      }

      /// <summary>
      /// Sets the scroll bar visibility and range for the current
      /// contents.
      /// </summary>
      private void SetScroll()
      {
         int totalHeightWithScroll = internalBorder + bars.Count *
          internalBorder;
         if (drawingMode == ExplorerBarMode.Search)
         {
            totalHeightWithScroll += internalBorder;
         }
         int totalHeightWithoutScroll = totalHeightWithScroll;
         foreach (ExplorerBar bar in bars)
         {
            if (bar.State == ExplorerBarState.Expanded)
            {
               totalHeightWithScroll += bar.HeightWithScroll;
               totalHeightWithoutScroll += bar.HeightWithoutScroll;
            }
            else
            {
               totalHeightWithScroll += bar.TitleHeightWithScroll;
               totalHeightWithoutScroll += bar.TitleHeightWithoutScroll;
            }
         }
         if (totalHeightWithoutScroll > ClientRectangle.Height)
         {
            // we need a scroll bar:
            int max = totalHeightWithScroll - ClientRectangle.Height;
            VerticalScrollBar.Visible = true;
            VerticalScrollBar.LargeChange = ClientRectangle.Height;
            VerticalScrollBar.Max = max;
            VerticalScrollBar.SmallChange = 24;
         }
         else
         {
            // no scroll bar is required:
            VerticalScrollBar.Value = 0;
            VerticalScrollBar.Visible = false;
         }
      }

      /// <summary>
      /// Gets an initialised <see cref="ExplorerBarDrawItemParams"/> object
      /// for the current bar state.
      /// </summary>
      /// <param name="graphics">Graphics object to render to</param>
      /// <returns>Initialised object</returns>
      private ExplorerBarDrawItemParams DrawItemParams(Graphics graphics)
      {
         int widthWithoutScroll = ClientRectangle.Width;
         int widthWithScroll = 0;
         bool scrollShowing = false;
         if (VerticalScrollBar.Visible)
         {
            widthWithScroll = widthWithoutScroll;
            widthWithoutScroll += SystemInformation.VerticalScrollBarWidth;
            scrollShowing = true;
         }
         else
         {
            widthWithScroll = widthWithoutScroll -
             SystemInformation.VerticalScrollBarWidth;
         }
         
         int top = internalBorder - VerticalScrollBar.Value;
         
         ExplorerBarDrawItemParams drawItemParams = new
          ExplorerBarDrawItemParams(
            graphics, 
            titleImageList, 
            itemImageList,
            Font, 
            widthWithoutScroll,
            widthWithScroll,
            scrollShowing,
            drawingStyle,
            drawingMode,
            (RightToLeft == RightToLeft.Yes),
            top,
            animBitmap,
            ShowFocusCues,
            ShowKeyboardCues
            );
         return drawItemParams;
      }

      /// <summary>
      /// Gets a preinitialised <see cref="ExplorerBarMeasureItemParams"/>
       object
      /// for the current bar state
      /// </summary>
      /// <param name="graphics">Graphics object to measure in</param>
      /// <returns>Initialised object</returns>
      private ExplorerBarMeasureItemParams MeasureItemParams(Graphics graphics)
      {
         int widthWithoutScroll = Size.Width;
         int widthWithScroll = Size.Width -
          SystemInformation.VerticalScrollBarWidth;

         ExplorerBarMeasureItemParams measureItemParams = new
          ExplorerBarMeasureItemParams(
            graphics, titleImageList, itemImageList,
            Font, widthWithoutScroll, widthWithScroll,
            drawingStyle, drawingMode);
         
         return measureItemParams;
      }

      /// <summary>
      /// Sets the tooltip to the specified text
      /// </summary>
      /// <param name="text">Tooltip text to display</param>
      private void setToolTip(
         string text
         )
      {
         if (toolTip != null) 
         {
            toolTip.SetToolTip(this, text);
         }
      }

      /// <summary>
      /// Returns the <see cref="ExplorerBar"/> at the specified location, if
       any,
      /// otherwise <c>null</c>.
      /// </summary>
      /// <param name="location">Location in the control to test.</param>
      /// <returns>Bar if found, otherwise null.</returns>
      private ExplorerBar HitTestBar(Point location)
      {
         ExplorerBar hitBar = null;
         foreach (ExplorerBar bar in bars)
         {
            if (bar.HitTest(location, ClientRectangle.Width,
             VerticalScrollBar.Visible))
            {
               hitBar = bar;
               break;
            }
         }
         return hitBar;
      }

      /// <summary>
      /// Returns the <see cref="ExplorerBarItem"/> at the specified location,
       if any,
      /// otherwise <c>null</c>.
      /// </summary>
      /// <param name="location">Location in the control to test.</param>
      /// <returns>Item if found, otherwise null.</returns>
      private ExplorerBarItem HitTestItem(Point location)
      {
         ExplorerBarItem hitItem = null;
         foreach (ExplorerBar bar in bars)
         {
            foreach (ExplorerBarItem item in bar.Items)
            {
               if (bar.State == ExplorerBarState.Expanded)
               {
                  if (item.HitTest(location, ClientRectangle.Width,
                   VerticalScrollBar.Visible))
                  {
                     hitItem = item;
                     break;
                  }
               }
            }
            if (hitItem != null)
            {
               break;
            }
         }
         return hitItem;
      }
      #endregion
   }
}