context: // *****************************************************************************
  // 
  //  (c) Crownwood Consulting Limited 2002-2003
  //  All rights reserved. The software and associated documentation 
  //  supplied hereunder are the proprietary information of Crownwood Consulting 
  //	Limited, Crownwood, Bracknell, Berkshire, England and are supplied subject 
  //  to licence terms.
  // 
  //  Magic Version 1.7.4.0 	www.dotnetmagic.com
  // *****************************************************************************
  
  using System;
  using System.IO;
  using System.Drawing;
  using System.Reflection;
  using System.Collections;
  using System.Drawing.Text;
  using System.Windows.Forms;
  using System.ComponentModel;
  using System.Drawing.Imaging;
  using System.Drawing.Drawing2D;
  using Microsoft.Win32;
  using Crownwood.Magic.Win32;
  using Crownwood.Magic.Menus;
  using Crownwood.Magic.Common;
  using Crownwood.Magic.Controls;
  using Crownwood.Magic.Collections;
  
  namespace Crownwood.Magic.Menus
  {
      [ToolboxBitmap(typeof(MenuControl))]
      [DefaultProperty("MenuCommands")]
      [DefaultEvent("PopupSelected")]
      [Designer(typeof(Crownwood.Magic.Menus.MenuControlDesigner))]
      public class MenuControl : ContainerControl, IMessageFilter
      {
          internal class MdiClientSubclass : NativeWindow
          {
              protected override void WndProc(ref Message m)
              {
                  switch(m.Msg)
                  {
                      case (int)Win32.Msgs.WM_MDISETMENU:
                      case (int)Win32.Msgs.WM_MDIREFRESHMENU:
                          return;
                  }
  
                  base.WndProc(ref m);
              }			
          }
  
          // Class constants
          protected const int _lengthGap = 3;
          protected const int _boxExpandUpper = 1;
          protected const int _boxExpandSides = 2;
          protected const int _shadowGap = 4;
          protected const int _shadowYOffset = 4;
          protected const int _separatorWidth = 15;
          protected const int _subMenuBorderAdjust = 2;
          protected const int _minIndex = 0;
          protected const int _restoreIndex = 1;
          protected const int _closeIndex = 2;
          protected const int _chevronIndex = 3;
          protected const int _buttonLength = 16;
          protected const int _chevronLength = 12;
          protected const int _pendantLength = 48;
          protected const int _pendantOffset = 3;
  
          // Class constant is marked as 'readonly' to allow non constant initialization
          protected readonly int WM_OPERATEMENU = (int)Win32.Msgs.WM_USER + 1;
  
          // Class fields
          protected static ImageList _menuImages = null;
          protected static bool _supportsLayered = false;
  
          // Instance fields
          protected int _rowWidth;
          protected int _rowHeight;
          protected int _trackItem;
          protected int _breadthGap;
          protected int _animateTime;
          protected IntPtr _oldFocus;
          protected Pen _controlLPen;
          protected bool _animateFirst;
          protected bool _selected;
          protected bool _multiLine;
          protected bool _mouseOver;
          protected bool _manualFocus;
          protected bool _drawUpwards;
  		protected bool _defaultFont;
          protected bool _defaultBackColor;
          protected bool _defaultTextColor;
          protected bool _defaultHighlightBackColor;
          protected bool _defaultHighlightTextColor;
          protected bool _defaultSelectedBackColor;
          protected bool _defaultSelectedTextColor;
          protected bool _defaultPlainSelectedTextColor;
          protected bool _plainAsBlock;
          protected bool _dismissTransfer;
          protected bool _ignoreMouseMove;
          protected bool _expandAllTogether;
          protected bool _rememberExpansion;
          protected bool _deselectReset;
          protected bool _highlightInfrequent;
  		protected bool _exitLoop;
          protected Color _textColor;
          protected Color _highlightBackColor;
          protected Color _useHighlightBackColor;
          protected Color _highlightTextColor;
          protected Color _highlightBackDark;
          protected Color _highlightBackLight;
          protected Color _selectedBackColor;
          protected Color _selectedTextColor;
          protected Color _plainSelectedTextColor;
          protected Form _activeChild;
          protected Form _mdiContainer;
  		protected GlyphFading _glyphFading;
  		protected VisualStyle _style;
          protected Direction _direction;
          protected PopupMenu _popupMenu;
          protected ArrayList _drawCommands;
          protected SolidBrush _controlLBrush;
          protected SolidBrush _backBrush;
          protected Animate _animate;
          protected Animation _animateStyle;
          internal MdiClientSubclass _clientSubclass;
          protected MenuCommand _chevronStartCommand;
          protected MenuCommandCollection _menuCommands;
  
          // Instance fields - pendant buttons
          protected InertButton _minButton;
          protected InertButton _restoreButton;
          protected InertButton _closeButton;
  
          // Instance fields - events
          public event CommandHandler Selected;
          public event CommandHandler Deselected;
  
          static MenuControl()
          {
              // Create a strip of images by loading an embedded bitmap resource
              _menuImages = ResourceHelper.LoadBitmapStrip(Type.GetType("Crownwood.Magic.Menus.MenuControl"),
                                                           "Crownwood.Magic.Resources.ImagesMenuControl.bmp",
                                                           new Size(_buttonLength, _buttonLength),
                                                           new Point(0,0));
  
              // We need to know if the OS supports layered windows
              _supportsLayered = (OSFeature.Feature.GetVersionPresent(OSFeature.LayeredWindows) != null);
          }
  
          public MenuControl()
          {
              // Set default values
              _trackItem = -1;
              _oldFocus = IntPtr.Zero;
              _minButton = null;
              _popupMenu = null;
              _activeChild = null;
              _closeButton = null;
              _controlLPen = null;
              _mdiContainer = null;
              _restoreButton = null;
              _controlLBrush = null;
              _chevronStartCommand = null;
              _animateFirst = true;
  			_exitLoop = false;
              _selected = false;
              _multiLine = false;
              _mouseOver = false;
  			_defaultFont = true;
              _manualFocus = false;
              _drawUpwards = false;
              _plainAsBlock = false;
              _clientSubclass = null;
              _ignoreMouseMove = false;
              _deselectReset = true;
              _expandAllTogether = true;
              _rememberExpansion = true;
              _highlightInfrequent = true;
              _dismissTransfer = false;
              _style = VisualStyle.IDE;
              _direction = Direction.Horizontal;
              _menuCommands = new MenuCommandCollection();
  			_glyphFading = GlyphFading.Default;
  			this.Dock = DockStyle.Top;
  			this.Cursor = System.Windows.Forms.Cursors.Arrow;
  			
              // Animation details
              _animateTime = 100;
              _animate = Animate.System;
              _animateStyle = Animation.System;
  
              // Prevent flicker with double buffering and all painting inside WM_PAINT
  			SetStyle(ControlStyles.DoubleBuffer | 
  					 ControlStyles.AllPaintingInWmPaint |
  					 ControlStyles.UserPaint, true);
  			
              // Should not be allowed to select this control
              SetStyle(ControlStyles.Selectable, false);
  
              // Hookup to collection events
              _menuCommands.Cleared += new CollectionClear(OnCollectionCleared);
              _menuCommands.Inserted += new CollectionChange(OnCollectionInserted);
              _menuCommands.Removed += new CollectionChange(OnCollectionRemoved);
  
  			// Need notification when the MenuFont is changed
  			Microsoft.Win32.SystemEvents.UserPreferenceChanged += 
  			    new UserPreferenceChangedEventHandler(OnPreferenceChanged);
  
              DefineColors();
              
              // Set the starting Font
              DefineFont(SystemInformation.MenuFont);
  
              // Do not allow tab key to select this control
              this.TabStop = false;
  
              // Default to one line of items
              this.Height = _rowHeight;
  
              // Add ourself to the application filtering list
              Application.AddMessageFilter(this);
          }
  
          protected override void Dispose(bool disposing)
          {
              if( disposing )
              {
                  // Remove notifications
                  Microsoft.Win32.SystemEvents.UserPreferenceChanged -= 
                      new UserPreferenceChangedEventHandler(OnPreferenceChanged);
              }
              base.Dispose( disposing );
          }
  
          [Category("Behaviour")]
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
          public MenuCommandCollection MenuCommands
          {
              get { return _menuCommands; }
          } 
  
          [Category("Appearance")]
          public VisualStyle Style
          {
              get { return _style; }
  			
              set
              {
                  if (_style != value)
                  {
                      _style = value;
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          public override Font Font
          {
              get { return base.Font; }
  			
              set
              {
  				if (value != base.Font)
  				{
  					_defaultFont = (value == SystemInformation.MenuFont);
  
  					DefineFont(value);
  
  					Recalculate();
  					Invalidate();
  				}
              }
          }
  
  		public override Color BackColor
  		{
  			get { return base.BackColor; }
  
  			set
  			{
  				if (value != base.BackColor)
  				{
  					_defaultBackColor = (value == SystemColors.Control);
                      base.BackColor = value;
                      _backBrush = new SolidBrush(base.BackColor);
                      
  					Recalculate();
  					Invalidate();
  				}
  			}
  		}
  
          private bool ShouldSerializeBackColor()
          {
              return this.BackColor != SystemColors.Control;
          }
  
          [Category("Appearance")]
          public Color TextColor
          {
              get { return _textColor; }
  
              set
              {
                  if (value != _textColor)
                  {
                      _textColor = value;
                      _defaultTextColor = (value == SystemColors.MenuText);
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializeTextColor()
          {
              return _textColor != SystemColors.MenuText;
          }
  
          [Category("Appearance")]
          public Color HighlightBackColor
          {
              get { return _highlightBackColor; }
  
              set
              {
                  if (value != _highlightBackColor)
                  {
                      _defaultHighlightBackColor = (value == SystemColors.Highlight);
                      DefineHighlightBackColors(value);                    
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializeHighlightBackColor()
          {
              return _highlightBackColor != SystemColors.Highlight;
          }
  
          [Category("Appearance")]
          public Color HighlightTextColor
          {
              get { return _highlightTextColor; }
  
              set
              {
                  if (value != _highlightTextColor)
                  {
                      _highlightTextColor = value;
                      _defaultHighlightTextColor = (value == SystemColors.MenuText);
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializeHighlightTextColor()
          {
              return _highlightTextColor != SystemColors.HighlightText;
          }
  
          [Category("Appearance")]
          public Color SelectedBackColor
          {
              get { return _selectedBackColor; }
  
              set
              {
                  if (value != _selectedBackColor)
                  {
                      DefineSelectedBackColors(value);
                      _defaultSelectedBackColor = (value == SystemColors.Control);
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializeSelectedBackColor()
          {
              return _selectedBackColor != SystemColors.Control;
          }
  
          [Category("Appearance")]
          public Color SelectedTextColor
          {
              get { return _selectedTextColor; }
  
              set
              {
                  if (value != _selectedTextColor)
                  {
                      _selectedTextColor = value;
                      _defaultSelectedTextColor = (value == SystemColors.MenuText);
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializeSelectedTextColor()
          {
              return _selectedTextColor != SystemColors.MenuText;
          }
  
          [Category("Appearance")]
          public Color PlainSelectedTextColor
          {
              get { return _plainSelectedTextColor; }
  
              set
              {
                  if (value != _plainSelectedTextColor)
                  {
                      _plainSelectedTextColor = value;
                      _defaultPlainSelectedTextColor = (value == SystemColors.ActiveCaptionText);
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          private bool ShouldSerializePlainSelectedTextColor()
          {
              return _plainSelectedTextColor != SystemColors.ActiveCaptionText;
          }
  
          [Category("Appearance")]
          [DefaultValue(false)]
          public bool PlainAsBlock
          {
              get { return _plainAsBlock; }
  
              set
              {
                  if (_plainAsBlock != value)
                  {
  	                _plainAsBlock = value;
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          [Category("Appearance")]
          [DefaultValue(false)]
          public bool MultiLine
          {
              get { return _multiLine; }
  
              set
              {
                  if (_multiLine != value)
                  {
                      _multiLine = value;
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          [Category("Appearance")]
          public Direction Direction
          {
              get { return _direction; }
  
              set
              {
                  if (_direction != value)
                  {
                      _direction = value;
  
                      Recalculate();
                      Invalidate();
                  }
              }
          }
  
          [Category("Behaviour")]
          [DefaultValue(true)]
          public bool RememberExpansion
          {
              get { return _rememberExpansion; }
              set { _rememberExpansion = value; }
          }
  
          [Category("Behaviour")]
          [DefaultValue(true)]
          public bool ExpandAllTogether
          {
              get { return _expandAllTogether; }
              set { _expandAllTogether = value; }
          }
          
          [Category("Behaviour")]
          [DefaultValue(true)]
          public bool DeselectReset
          {
              get { return _deselectReset; }
              set { _deselectReset = value; }
          }
          
          [Category("Behaviour")]
          [DefaultValue(true)]
          public bool HighlightInfrequent
          {
              get { return _highlightInfrequent; }
              set { _highlightInfrequent = value; }
          }
  
          public override DockStyle Dock
          {
              get { return base.Dock; }
  
              set
              {
                  base.Dock = value;
  
                  switch(value)
                  {
                      case DockStyle.None:
                          _direction = Direction.Horizontal;
                          break;
                      case DockStyle.Top:
                      case DockStyle.Bottom:
                          this.Height = 0;
                          _direction = Direction.Horizontal;
                          break;
                      case DockStyle.Left:
                      case DockStyle.Right:
                          this.Width = 0;
                          _direction = Direction.Vertical;
                          break;
                  }
  
                  Recalculate();
                  Invalidate();
              }
          }
  
          [Category("Animate")]
          [DefaultValue(typeof(Animate), "System")]
          public Animate Animate
          {
              get { return _animate; }
              set { _animate = value; }
          }
  
          [Category("AnimateTime")]
          public int AnimateTime
          {
              get { return _animateTime; }
              set { _animateTime = value; }
          }
  
          [Category("AnimateStyle")]
          public Animation AnimateStyle
          {
              get { return _animateStyle; }
              set { _animateStyle = value; }
          }
  
  		[Category("Appearance")]
  		[DefaultValue(GlyphFading.Default)]
  		public GlyphFading GlyphFading
  		{
  			get { return _glyphFading; }
  			set { _glyphFading = value; }
  		}
  
  		[Category("Behaviour")]
          [DefaultValue(null)]
          public Form MdiContainer
          {
              get { return _mdiContainer; }
  			
              set
              {
                  if (_mdiContainer != value)
                  {
                      if (_mdiContainer != null)
                      {
                          // Unsubclass from MdiClient and then remove object reference
                          _clientSubclass.ReleaseHandle();
                          _clientSubclass = null;
  
                          // Remove registered events
                          _mdiContainer.MdiChildActivate -= new EventHandler(OnMdiChildActivate);
  
                          RemovePendantButtons();
                      }
  
                      _mdiContainer = value;
  
                      if (_mdiContainer != null)
                      {
                          CreatePendantButtons();
  
                          foreach(Control c in _mdiContainer.Controls)
                          {
                              MdiClient client = c as MdiClient;
  
                              if (client != null)
                              {
                                  // We need to subclass the MdiClient to prevent any attempt
                                  // to change the menu for the container Form. This prevents
                                  // the system from automatically adding the pendant.
                                  _clientSubclass = new MdiClientSubclass();
                                  _clientSubclass.AssignHandle(client.Handle);
                              }
                          }
  
                          // Need to be informed of the active child window
                          _mdiContainer.MdiChildActivate += new EventHandler(OnMdiChildActivate);
                      }
                  }
              }
          }
  
          protected void DefineColors()
          {
              // Define starting text colors
              _defaultTextColor = true;
              _defaultHighlightTextColor = true;
              _defaultSelectedTextColor = true;
              _defaultPlainSelectedTextColor = true;
              _textColor = SystemColors.MenuText;
              _highlightTextColor = SystemColors.MenuText;
              _selectedTextColor = SystemColors.MenuText;
  			_plainSelectedTextColor = SystemColors.ActiveCaptionText;
  
              // Define starting back colors
              _defaultBackColor = true;
              _defaultHighlightBackColor = true;
              _defaultSelectedBackColor = true;
              base.BackColor = SystemColors.Control;
              _backBrush = new SolidBrush(base.BackColor);
              _highlightBackColor = SystemColors.Highlight;            
              DefineHighlightBackColors(SystemColors.Highlight);
              DefineSelectedBackColors(SystemColors.Control);
          }
          
          public void ResetColors()
          {
              this.BackColor = SystemColors.Control;
              this.TextColor = SystemColors.MenuText;
              this.HighlightBackColor = SystemColors.Highlight;            
              this.HighlightTextColor = SystemColors.MenuText;
              this.SelectedBackColor = SystemColors.Control;
              this.SelectedTextColor = SystemColors.MenuText;
          }
  
  		protected void DefineFont(Font newFont)
  		{
  			base.Font = newFont;
  
  			_breadthGap = (this.Font.Height / 3) + 1;
  
              // Calculate the initial height/width of the control
              _rowWidth = _rowHeight = this.Font.Height + _breadthGap * 2 + 1;
  		}
  
          protected void DefineSelectedBackColors(Color baseColor)
          {
              _selectedBackColor = baseColor;
  			Color lightColor = ColorHelper.CalculateColor(baseColor, Color.White, 200);
  			_controlLPen = new Pen(lightColor);
              _controlLBrush = new SolidBrush(lightColor);
          }
  
          protected void DefineHighlightBackColors(Color baseColor)
          {
              _highlightBackColor = baseColor;
          
              if (_defaultHighlightBackColor)
              {
                  _highlightBackDark = SystemColors.Highlight;
                  _highlightBackLight = ColorHelper.CalculateColor(_highlightBackDark, Color.White, 70);
              }
              else
              {
                  _highlightBackDark = ControlPaint.Dark(baseColor);
                  _highlightBackLight = baseColor;
              }
          }
  
          public virtual void OnSelected(MenuCommand mc)
          {
              // Any attached event handlers?
              if (Selected != null)
                  Selected(mc);
          }
  
          public virtual void OnDeselected(MenuCommand mc)
          {
              // Any attached event handlers?
              if (Deselected != null)
                  Deselected(mc);
          }
  
          protected void OnCollectionCleared()
          {
              // Reset state ready for a recalculation
              Deselect();
              RemoveItemTracking();
  
              Recalculate();
              Invalidate();
          }
  
          protected void OnCollectionInserted(int index, object value)
          {
              MenuCommand mc = value as MenuCommand;
  
              // We need notification whenever the properties of this command change
              mc.PropertyChanged += new MenuCommand.PropChangeHandler(OnCommandChanged);
  				
              // Reset state ready for a recalculation
              Deselect();
              RemoveItemTracking();
  
              Recalculate();
              Invalidate();
          }
  
          protected void OnCollectionRemoved(int index, object value)
          {
              // Reset state ready for a recalculation
              Deselect();
              RemoveItemTracking();
  
              Recalculate();
              Invalidate();
          }
  
          protected void OnCommandChanged(MenuCommand item, MenuCommand.Property prop)
          {
              Recalculate();
              Invalidate();
          }
  
          protected void OnMdiChildActivate(object sender, EventArgs e)
          {
              // Unhook from event
              if (_activeChild != null)
                  _activeChild.SizeChanged -= new EventHandler(OnMdiChildSizeChanged);
  
              // Remember the currently active child form
              _activeChild = _mdiContainer.ActiveMdiChild;
  
              // Need to know when window becomes maximized
              if (_activeChild != null)
                  _activeChild.SizeChanged += new EventHandler(OnMdiChildSizeChanged);
  
              // Might be a change in pendant requirements
              Recalculate();
              Invalidate();
          }
  
          protected void OnMdiChildSizeChanged(object sender, EventArgs e)
          {
              // Has window changed to become maximized?
              if (_activeChild.WindowState == FormWindowState.Maximized)
              {
                  // Reflect change in menu
                  Recalculate();
                  Invalidate();
              }
          }
  
          protected void OnMdiMin(object sender, EventArgs e)
          {
              if (_activeChild != null)
              {
                  _activeChild.WindowState = FormWindowState.Minimized;
  
                  // Reflect change in menu
                  Recalculate();
                  Invalidate();
              }
          }
  
          protected void OnMdiRestore(object sender, EventArgs e)
          {
              if (_activeChild != null)
              {
                  _activeChild.WindowState = FormWindowState.Normal;
  
                  // Reflect change in menu
                  Recalculate();
                  Invalidate();
              }
          }
  
          protected void OnMdiClose(object sender, EventArgs e)
          {
              if (_activeChild != null)
              {
                  _activeChild.Close();
  
                  // Reflect change in menu
                  Recalculate();
                  Invalidate();
              }
          }
  
          protected void CreatePendantButtons()
          {
              // Create the objects
              _minButton = new InertButton(_menuImages, _minIndex);
              _restoreButton = new InertButton(_menuImages, _restoreIndex);
              _closeButton = new InertButton(_menuImages, _closeIndex);
  
              // Define the constant sizes
              _minButton.Size = new Size(_buttonLength, _buttonLength);
              _restoreButton.Size = new Size(_buttonLength, _buttonLength);
              _closeButton.Size = new Size(_buttonLength, _buttonLength);
  
              // Default their position so they are not visible
              _minButton.Location = new Point(-_buttonLength, -_buttonLength);
              _restoreButton.Location = new Point(-_buttonLength, -_buttonLength);
              _closeButton.Location = new Point(-_buttonLength, -_buttonLength);
  
              // Hookup event handlers
              _minButton.Click += new EventHandler(OnMdiMin);
              _restoreButton.Click += new EventHandler(OnMdiRestore);
              _closeButton.Click += new EventHandler(OnMdiClose);
  
              // Add to display
              this.Controls.AddRange(new Control[]{_minButton, _restoreButton, _closeButton});
          }
  
          protected void RemovePendantButtons()
          {
              // Unhook event handlers
              _minButton.Click -= new EventHandler(OnMdiMin);
              _restoreButton.Click -= new EventHandler(OnMdiRestore);
              _closeButton.Click -= new EventHandler(OnMdiClose);
  
              // Remove from display
  
  			// Use helper method to circumvent form Close bug
  			ControlHelper.Remove(this.Controls, _minButton);
  			ControlHelper.Remove(this.Controls, _restoreButton);
  			ControlHelper.Remove(this.Controls, _closeButton);
  
              // Release resources
              _minButton.Dispose();
              _restoreButton.Dispose();
              _closeButton.Dispose();
  
              // Remove references
              _minButton = null;
              _restoreButton = null;
              _closeButton = null;
          }
          
          protected override void OnEnabledChanged(EventArgs e)
          {
              base.OnEnabledChanged(e);
  
              // Have we become disabled?
              if (!this.Enabled)
              {
                  // Is an item selected?
                  if (_selected)
                  {
                      // Is a popupMenu showing?
                      if (_popupMenu != null)
                      {
                          // Dismiss the submenu
                          _popupMenu.Dismiss();
  
                          // No reference needed
                          _popupMenu = null;
                      }
  
                      // Reset state
                      Deselect();
                      _drawUpwards = false;
  
                      SimulateReturnFocus();
                  }
              }
  
              // Do not draw any item as being tracked
              RemoveItemTracking();
  
              // Change in state changes the way items are drawn
              Invalidate();
          }
  
          internal void OnWM_MOUSEDOWN(Win32.POINT screenPos)
          {
              // Convert the mouse position to screen coordinates
              User32.ScreenToClient(this.Handle, ref screenPos);
  
              OnProcessMouseDown(screenPos.x, screenPos.y);
          }
  
          protected override void OnMouseDown(MouseEventArgs e)
          {
              OnProcessMouseDown(e.X, e.Y);
  
              base.OnMouseDown(e);
          }
  		
          protected void OnProcessMouseDown(int xPos, int yPos)
          {
              Point pos = new Point(xPos, yPos);
  
              for(int i=0; i<_drawCommands.Count; i++)
              {
                  DrawCommand dc = _drawCommands[i] as DrawCommand;
  
                  // Find the DrawCommand this is over
                  if (dc.SelectRect.Contains(pos) && dc.Enabled)
                  {
                      // Is an item already selected?
                      if (_selected)
                      {
                          // Is it this item that is already selected?
                          if (_trackItem == i)
                          {
                              // Is a popupMenu showing
                              if (_popupMenu != null)
                              {
                                  // Dismiss the submenu
                                  _popupMenu.Dismiss();
  
                                  // No reference needed
                                  _popupMenu = null;
                              }
                          }
                      }
                      else
                      {
                          // Select the tracked item
                          _selected = true;
                          _drawUpwards = false;
  								
                          // Is there a change in tracking?
                          if (_trackItem != i)
                          {
                              // Modify the display of the two items 
                              _trackItem = SwitchTrackingItem(_trackItem, i);
                          }
                          else
                          {
                              // Update display to show as selected
                              DrawCommand(_trackItem, true);
                          }
  
                          // Is there a submenu to show?
                          if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
                              User32.PostMessage(this.Handle, WM_OPERATEMENU, 1, 0);
                      }
  
                      break;
                  }
              }
          }
  
          protected override void OnMouseUp(MouseEventArgs e)
          {
              // Is an item currently being tracked?
              if (_trackItem != -1)
              {
                  // Is it also selected?
                  if (_selected == true)
                  {
                      // Is it also showing a submenu
                      if (_popupMenu == null)
                      {
                          // Deselect the item
                          Deselect();
                          _drawUpwards = false;
  
                          DrawCommand(_trackItem, true);
  
                          SimulateReturnFocus();
                      }
                  }
              }
  
              base.OnMouseUp(e);
          }
  
          internal void OnWM_MOUSEMOVE(Win32.POINT screenPos)
          {
              // Convert the mouse position to screen coordinates
              User32.ScreenToClient(this.Handle, ref screenPos);
  
              OnProcessMouseMove(screenPos.x, screenPos.y);
          }
  
          protected override void OnMouseMove(MouseEventArgs e)
          {
              // Sometimes we need to ignore this message
              if (_ignoreMouseMove)
                  _ignoreMouseMove = false;
              else
                  OnProcessMouseMove(e.X, e.Y);
  
              base.OnMouseMove(e);
          }
  
          protected void OnProcessMouseMove(int xPos, int yPos)
          {
              // Sometimes we need to ignore this message
              if (_ignoreMouseMove)
                  _ignoreMouseMove = false;
              else
              {
                  // Is the first time we have noticed a mouse movement over our window
                  if (!_mouseOver)
                  {
                      // Create the structure needed for User32 call
                      Win32.TRACKMOUSEEVENTS tme = new Win32.TRACKMOUSEEVENTS();
  
                      // Fill in the structure
                      tme.cbSize = 16;									
                      tme.dwFlags = (uint)Win32.TrackerEventFlags.TME_LEAVE;
                      tme.hWnd = this.Handle;								
                      tme.dwHoverTime = 0;								
  
                      // Request that a message gets sent when mouse leaves this window
                      User32.TrackMouseEvent(ref tme);
  
                      // Yes, we know the mouse is over window
                      _mouseOver = true;
                  }
  
                  Form parentForm = this.FindForm();
  
                  // Only hot track if this Form is active
                  if ((parentForm != null) && parentForm.ContainsFocus)
                  {
                      Point pos = new Point(xPos, yPos);
  
                      int i = 0;
  
                      for(i=0; i<_drawCommands.Count; i++)
                      {
                          DrawCommand dc = _drawCommands[i] as DrawCommand;
  
                          // Find the DrawCommand this is over
                          if (dc.SelectRect.Contains(pos) && dc.Enabled)
                          {
                              // Is there a change in selected item?
                              if (_trackItem != i)
                              {
                                  // We are currently selecting an item
                                  if (_selected)
                                  {
                                      if (_popupMenu != null)
                                      {
                                          // Note that we are dismissing the submenu but not removing
                                          // the selection of items, this flag is tested by the routine
                                          // that will return because the submenu has been finished
                                          _dismissTransfer = true;
  
                                          // Dismiss the submenu
                                          _popupMenu.Dismiss();
  		
                                          // Default to downward drawing
                                          _drawUpwards = false;
                                      }
  
                                      // Modify the display of the two items 
                                      _trackItem = SwitchTrackingItem(_trackItem, i);
  
                                      // Does the newly selected item have a submenu?
                                      if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))	
                                          User32.PostMessage(this.Handle, WM_OPERATEMENU, 1, 0);
                                  }
                                  else
                                  {
                                      // Modify the display of the two items 
                                      _trackItem = SwitchTrackingItem(_trackItem, i);
                                  }
                              }
  
                              break;
                          }
                      }
  
                      // If not in selected mode
                      if (!_selected)
                      {
                          // None of the commands match?
                          if (i == _drawCommands.Count)
                          {
                              // If we have the focus then do not change the tracked item
                              if (!_manualFocus)
                              {
                                  // Modify the display of the two items 
                                  _trackItem = SwitchTrackingItem(_trackItem, -1);
                              }
                          }
                      }
                  }
              }
          }
  
          protected override void OnMouseLeave(EventArgs e)
          {
              _mouseOver = false;
  
              // If we manually grabbed focus then do not switch
              // selection when the mouse leaves the control area
              if (!_manualFocus)
              {
                  if (_trackItem != -1)
                  {
                      // If an item is selected then do not change tracking item when the 
                      // mouse leaves the control area, as a popup menu might be showing and 
                      // so keep the tracking and selection indication visible
                      if (_selected == false)
                          _trackItem = SwitchTrackingItem(_trackItem, -1);
                  }
              }
  
              base.OnMouseLeave(e);
          }
  
          protected override void OnResize(EventArgs e)
          {
              Recalculate();
  
              // Any resize of control should redraw all of it otherwise when you 
              // stretch to the right it will not paint correctly as we have a one
              // pixel gap between text and min button which is not honoured otherwise
              this.Invalidate();
  
              base.OnResize(e);
          }
  
          internal void DrawSelectionUpwards()
          {
              // Double check the state is correct for this method to be called
              if ((_trackItem != -1) && (_selected))
              {
                  // This flag is tested in the DrawCommand method
                  _drawUpwards = true;
  
                  // Force immediate redraw of the item
                  DrawCommand(_trackItem, true);
              }
          }
  
          protected void Deselect()
          {
              // The next submenu should be animated
              _animateFirst = true;
  
              // Remove selection state
              _selected = false;
              
              // Should expansion items be reset on deselection?
              if (_deselectReset)
              {
                  // Set everything to expanded
                  SetAllCommandsExpansion(_menuCommands, false);
              }
          }
  
          protected void Recalculate()
          {
              int length;
  
              if (_direction == Direction.Horizontal)
                  length = this.Width;
              else 
                  length = this.Height;
  
              // Is there space for any commands?
              if (length > 0)
              {
                  // Count the number of rows needed
                  int rows = 0;
  
                  // Number of items on this row
                  int columns = 0;
  
                  // Create a collection of drawing objects
                  _drawCommands = new ArrayList();
  
                  // Minimum length is a gap on either side of the text
                  int cellMinLength = _lengthGap * 2;
  
                  // Each cell is as broad as the whole control
                  int cellBreadth = this.Height;
  				
                  // Accumulate starting position of each cell
                  int lengthStart = 0;
  
  				// Allow enough space to draw a chevron
                  length -= (cellMinLength + _chevronLength);
  
                  bool showPendant = ((rows == 0) && (_activeChild != null));
  
  				// If we are showing on a single line but the active child is not 
  				// currently maximized then we can show a menu item in pendant space
  				if (showPendant && !_multiLine && (_activeChild.WindowState != FormWindowState.Maximized))
  					showPendant = false;
  
                  // Pendant positioning information
                  int xPos = 0; 
                  int yPos = 0;
                  int xInc = 0;
                  int yInc = 0;
  
                  // First line needs extra space for pendant
                  if (showPendant)
                  {
                      length -= (_pendantLength + _pendantOffset + _shadowGap);
  
                      bool popupStyle = (_style == VisualStyle.IDE);
                      int borderWidth = (_style == VisualStyle.IDE) ? 1 : 2;
  
                      // Define the correct visual style
                      _minButton.PopupStyle = popupStyle;
                      _restoreButton.PopupStyle = popupStyle;
                      _closeButton.PopupStyle = popupStyle;
  
                      // Define correct border width
                      _minButton.BorderWidth = borderWidth;
                      _restoreButton.BorderWidth = borderWidth;
                      _closeButton.BorderWidth = borderWidth;
  
                      if (_direction == Direction.Horizontal)
                      {
                          xPos = this.Width - _pendantOffset - _buttonLength;
                          yPos = _pendantOffset;
                          xInc = -_buttonLength;
                      }
                      else
                      {
                          xPos = _pendantOffset;
                          yPos = this.Height - _pendantOffset - _buttonLength;
                          yInc = -_buttonLength;
                      }
                  }
  
                  // Assume chevron is not needed by default
                  _chevronStartCommand = null;
  
                  using(Graphics g = this.CreateGraphics())
                  {
                      // Count the item we are processing
                      int index = 0;
  
                      foreach(MenuCommand command in _menuCommands)
                      {
                          // Give the command a chance to update its state
                          command.OnUpdate(EventArgs.Empty);
  
                          // Ignore items that are marked as hidden
                          if (!command.Visible)
                              continue;
  
                          int cellLength = 0;
  
                          // Is this a separator?
                          if (command.Text == "-")
                              cellLength = _separatorWidth;
                          else
                          {
                              // Calculate the text width of the cell
                              SizeF dimension = g.MeasureString(command.Text, this.Font);
  
                              // Always add 1 to ensure that rounding is up and not down
                              cellLength = cellMinLength + (int)dimension.Width + 1;
                          }
  
                          Rectangle cellRect;
  
                          // Create a new position rectangle
                          if (_direction == Direction.Horizontal)
                              cellRect = new Rectangle(lengthStart, _rowHeight * rows, cellLength, _rowHeight);
                          else
                              cellRect = new Rectangle(_rowWidth * rows, lengthStart, _rowWidth, cellLength);
  
                          lengthStart += cellLength;
                          columns++;
  
                          // If this item is overlapping the control edge and it is not the first
                          // item on the line then we should wrap around to the next row.
                          if ((lengthStart > length) && (columns > 1))
                          {
                              if (_multiLine)
                              {
                                  // Move to next row
                                  rows++;
  
                                  // Reset number of items on this column
                                  columns = 1;
  
                                  // Reset starting position of next item
                                  lengthStart = cellLength;
  
                                  // Reset position of this item
                                  if (_direction == Direction.Horizontal)
                                  {
                                      cellRect.X = 0;
                                      cellRect.Y += _rowHeight;
                                  }
                                  else
                                  {
                                      cellRect.X += _rowWidth;
                                      cellRect.Y = 0;
                                  }
  
                                  // Only the first line needs extra space for pendant
                                  if (showPendant && (rows == 1))
                                      length += (_pendantLength + _pendantOffset);
                              }
                              else
                              {
                                  // Is a tracked item being make invisible
                                  if (index <= _trackItem)
                                  {
                                      // Need to remove tracking of this item
                                      RemoveItemTracking();
                                  }
  
                                  // Remember which item is first for the chevron submenu
                                  _chevronStartCommand = command;
  
                                  if (_direction == Direction.Horizontal)
                                  {
                                      cellRect.Y = 0;
                                      cellRect.Width = cellMinLength + _chevronLength;
                                      cellRect.X = this.Width - cellRect.Width;
                                      cellRect.Height = _rowHeight;
                                      xPos -= cellRect.Width;
                                  }
                                  else
                                  {
                                      cellRect.X = 0;
                                      cellRect.Height = cellMinLength + _chevronLength;
                                      cellRect.Y = this.Height - (cellMinLength + _chevronLength);
                                      cellRect.Width = _rowWidth;
                                      yPos -= cellRect.Height;
                                  }
  
                                  // Create a draw command for this chevron
                                  _drawCommands.Add(new DrawCommand(cellRect));
  
                                  // Exit, do not add the current item or any afterwards
                                  break;
                              }
                          }
  
  						Rectangle selectRect = cellRect;
  
  						// Selection rectangle differs from drawing rectangle with IDE, because pressing the
  						// mouse down causes the menu to appear and because the popup menu appears drawn slightly
  						// over the drawing area the mouse up might select the first item in the popup. 
  						if (_style == VisualStyle.IDE)
  						{
  							// Modify depending on orientation
  							if (_direction == Direction.Horizontal)
  								selectRect.Height -= (_lengthGap + 2);
  							else
  								selectRect.Width -= _breadthGap;
  						}
  
                          // Create a drawing object
                          _drawCommands.Add(new DrawCommand(command, cellRect, selectRect));
  
                          index++;
                      }
                  }
  
                  // Position the pendant buttons
                  if (showPendant)
                  {
                      if (_activeChild.WindowState == FormWindowState.Maximized)
                      {
                          // Window maximzied, must show the buttons
                          if (!_minButton.Visible)
                          {
                              _minButton.Show();
                              _restoreButton.Show();
                              _closeButton.Show();
                          }
  	
                          // Only enabled minimize box if child is allowed to be minimized
                          _minButton.Enabled = _activeChild.MinimizeBox;
  
                          _closeButton.Location = new Point(xPos, yPos);
  
                          xPos += xInc; yPos += yInc;
                          _restoreButton.Location = new Point(xPos, yPos);
  
                          xPos += xInc; yPos += yInc;
                          _minButton.Location = new Point(xPos, yPos);
                      }
                      else
                      {
                          // No window is maximized, so hide the buttons
                          if (_minButton.Visible)
                          {
                              _minButton.Hide();
                              _restoreButton.Hide();
                              _closeButton.Hide();
                          }
                      }
                  }
                  else
                  {
                      // No window is maximized, so hide the buttons
                      if ((_minButton != null) && _minButton.Visible)
                      {
                          _minButton.Hide();
                          _restoreButton.Hide();
                          _closeButton.Hide();
                      }
                  }
  
                  if (_direction == Direction.Horizontal)
                  {
                      int controlHeight = (rows + 1) * _rowHeight;
  
                      // Ensure the control is the correct height
                      if (this.Height != controlHeight)
                          this.Height = controlHeight;
                  }
                  else
                  {
                      int controlWidth = (rows + 1) * _rowWidth;
  
                      // Ensure the control is the correct width
                      if (this.Width != controlWidth)
                          this.Width = controlWidth;
                  }				
              }
          }
  
          protected void DrawCommand(int drawItem, bool tracked)
          {
              // Create a graphics object for drawing
              using(Graphics g = this.CreateGraphics())
                  DrawSingleCommand(g, _drawCommands[drawItem] as DrawCommand, tracked);
          }
  
          internal void DrawSingleCommand(Graphics g, DrawCommand dc, bool tracked)
          {
              Rectangle drawRect = dc.DrawRect;
              MenuCommand mc = dc.MenuCommand;
  
              // Copy the rectangle used for drawing cell
              Rectangle shadowRect = drawRect;
  
              // Expand to right and bottom to cover the area used to draw shadows
              shadowRect.Width += _shadowGap;
              shadowRect.Height += _shadowGap;
  
              if (!dc.Separator)
              {
                  Rectangle textRect;
  
                  // Text rectangle size depends on type of draw command we are drawing
                  if (dc.Chevron)
                  {
                      // Create chevron drawing rectangle
                      textRect = new Rectangle(drawRect.Left + _lengthGap, drawRect.Top + _boxExpandUpper,
                                               drawRect.Width - _lengthGap * 2, drawRect.Height - (_boxExpandUpper * 2));
                  }
                  else
                  {
                      // Create text drawing rectangle
                      textRect = new Rectangle(drawRect.Left + _lengthGap, drawRect.Top + _lengthGap,
                                               drawRect.Width - _lengthGap * 2, drawRect.Height - _lengthGap * 2);
                  }
  
                  if (dc.Enabled)
                  {
                      // Draw selection 
                      if (tracked)
                      {
                          Rectangle boxRect;
  
                          // Create the rectangle for box around the text
                          if (_direction == Direction.Horizontal)
                          {
                              boxRect = new Rectangle(textRect.Left - _boxExpandSides,
                                                      textRect.Top - _boxExpandUpper,
                                                      textRect.Width + _boxExpandSides * 2,
                                                      textRect.Height + _boxExpandUpper);
                          }
                          else
                          {					
                              if (!dc.Chevron)
                              {
                                  boxRect = new Rectangle(textRect.Left,
                                                          textRect.Top - _boxExpandSides,
                                                          textRect.Width - _boxExpandSides,
                                                          textRect.Height + _boxExpandSides * 2);
                              }
                              else
                                  boxRect = textRect;
                          }
  
                          switch(_style)
                          {
                              case VisualStyle.IDE:
                                  if (_selected)
                                  {
                                      // Fill the entire inside
                                      g.FillRectangle(Brushes.White, boxRect);
                                      g.FillRectangle(_controlLBrush, boxRect);
  								
                                      Color extraColor = Color.FromArgb(64, 0, 0, 0);
                                      Color darkColor = Color.FromArgb(48, 0, 0, 0);
                                      Color lightColor = Color.FromArgb(0, 0, 0, 0);
                  
                                      int rightLeft = boxRect.Right + 1;
                                      int rightBottom = boxRect.Bottom;
  
  									if (_drawUpwards && (_direction == Direction.Horizontal))                                    
  									{
                                          // Draw the box around the selection area
                                          using(Pen dark = new Pen(ControlPaint.Dark(_selectedBackColor)))
                                              g.DrawRectangle(dark, boxRect);
  
  										if (dc.SubMenu)
  										{
  											// Right shadow
  											int rightTop = boxRect.Top;
  											int leftLeft = boxRect.Left + _shadowGap;
  
  											// Bottom shadow
  											int top = boxRect.Bottom + 1;
  											int left = boxRect.Left + _shadowGap;
  											int width = boxRect.Width + 1;
  											int height = _shadowGap;
  
  											Brush rightShadow;
  											Brush bottomLeftShadow;
  											Brush bottomShadow;
  											Brush bottomRightShadow;
  
  											// Decide if we need to use an alpha brush
  											if (_supportsLayered)
  											{
  												// Create brushes
  												rightShadow = new LinearGradientBrush(new Point(rightLeft, 9999),
  																					  new Point(rightLeft + _shadowGap, 9999),
  																					  darkColor, lightColor);
  
  												bottomLeftShadow = new LinearGradientBrush(new Point(left + _shadowGap, top - _shadowGap),
  																						   new Point(left, top + height),
  																						   extraColor, lightColor);
  
  												bottomRightShadow = new LinearGradientBrush(new Point(left + width - _shadowGap - 2, top - _shadowGap - 2),
  
gt: 																							new Point(left + width, top + height),